8

I'm aware that I could use something called std::vector, but I'm afraid it's not possible because of the course restrictions.

I need to make a dynamic extensible array of objects. The array should grow and grow when new objects need to be stored.

Here is the class that the array belongs to:

class TransactionList
{
    private:
        Transaction *trans;
        int amountTransactions;
        Transaction newTrans;

    public:
        TransactionList();
        ~TransactionList();
        void read( istream &is );
        void write( ostream &os );
        void add( Transaction & newTrans ); 
        double totalExpenses();
        double hasPaid( string namnet );
        double isDebted( string namnet );
        //PersonList FixPersons();
 };

The method "void add ( Transaction & newTrans )" is the one I need. And yes, I seriously have to do it pointer-style.

So far this method is totally incomplete and just not even close to functional. I've tried several different ways, but end up with a runtime error or just bollocks result.

void TransactionList::add(Transaction & newTrans)
{
    Transaction* tempArrPtr;

    amountTransactions++;
    trans = new Transaction[amountTransactions]
    trans[amountTransactions - 1] = newTrans;
}

What I want the method to do is to build an array of of Transaction-objects and grow in size while it gets more objects.

I hope I've written about my problem clearly and wish someone could give me a good answer. I tried Googling, but I'm still stuck - otherwise I wouldn't have bothered asking :p

Also if someone could give some pointers about copy constructors, I'd be very thankful. In our course material they pretty much didn't even show what a copy constructor should look like. Just like "You need copy constuctors for deep copying, good luck!"

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
JKase
  • 157
  • 2
  • 10
  • 3
    There are some good questions around here about the "rule of three". Read them carefully. Then, read about `std::vector`. – Alexandre C. Jun 04 '11 at 20:25
  • 1
    [Here](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) is the one people from Stackoverflow put together for questions like this one. – Alexandre C. Jun 04 '11 at 20:25
  • just try copying what you need from STL vector class. – Ali1S232 Jun 04 '11 at 20:26
  • 3
    @Gajet: this is not a good idea. Use `std::vector`, don't copy it. – Alexandre C. Jun 04 '11 at 20:26
  • 3
    @Alecandre : after the first piece of code he seid he needs to do it pointer style, I didn't mean to copy it just use the idea vector used. – Ali1S232 Jun 04 '11 at 20:28
  • What's the purpose of newTrans ? – ysdx Jun 04 '11 at 20:28
  • I'm fully aware of the existance of something called std::vector that would suit my purpose just fine, but sadly I have to do the assignment in light of the course restrictions and guidelines, so it's not possible for me to use std::vector in this program. – JKase Jun 04 '11 at 20:31
  • @ysdx: newTrans is a Transaction-object. – JKase Jun 04 '11 at 20:32
  • The whole code can be seen on Ideone: http://ideone.com/8FmEG – JKase Jun 04 '11 at 20:38
  • For the reference, here's the same program I did earlier, but with static arrays: http://ideone.com/K64SC It might give some reference as to what I'm doing, but I know it's a god forsaken mess of Swedish and English :D – JKase Jun 04 '11 at 20:51
  • The question was more like "Why do you need it ?" – ysdx Jun 04 '11 at 21:55

3 Answers3

5

You should add a maxTransactions variable, which would indicate the allocated length of your trans* array, and initialize both ammountTransactions and maxTransactions with 0.

Your array would automatically double its size when we reach the limits of trans


void TransactionList::add(Transaction & newTrans)
{
    if(amountTransactions == maxTransactions){ //we've reached the capacity of trans
        //allocate a new array
        Transaction* nuTrans = new Transaction[maxTransactions*2+1];
        //copy the old values of trans into nuTrans
        memcpy(nuTrans, trans, sizeof(Transaction)*maxTransactions);
        //deallocate the old trans array
        delete []trans;
        //set trans to point at your newly allocated array
        trans = nuTrans;
        //update maxTransactions
        maxTransactions = maxTransactions*2+1;
    }

    trans[amountTransactions] = newTrans;
    amountTransactions++;
}


PS. I wrote it directly here, I didn't check it if it compiles as a whole or didn't debug the code. But I present it as an idea you could follow

Edit: Working example @ http://ideone.com/uz1mE

Matyas
  • 13,473
  • 3
  • 60
  • 73
  • But I don't see where maxTransaction is assigned with the new capacity after the realloc! btw: maxTransaction*2+1 : why "+1"? (just curious) – vines Jun 04 '11 at 20:39
  • Because I stated that we start with both vars =0, and no matter how many times you'd double 0, you'd end up with 0 :). And this way we don't need special initialization code + the doubling of the size of the array is pretty efficient AFAIK – Matyas Jun 04 '11 at 20:43
  • Thanks for your answer matyas! I thought something along those lines also. But the thing is, I have to start with an array that holds just one object and grows one by one as more objects come so it takes as little memory as possible. I really feel this course forces to do things in awkward ways not compliant to good programming methods, but as a student I think I just have to comply :) So no checking of upper limits, me thinks, just plain grow the array by one every time. – JKase Jun 04 '11 at 20:47
  • Well then you can do `maxTransactions+1` instead of `maxTransactions*2+1` but that adds a lot of overhead because you copy the whole array every time a new item gets added – Matyas Jun 04 '11 at 20:51
  • Alright, yeah. Care if I ask - what's memcpy? Haven't run into it so far at least. Can I accomplish the copying with a simple for loop instead or does something go bollocks? I mostly mean shallow copy vs deep copy? – JKase Jun 04 '11 at 20:57
  • Sure you can use a simple for loop. But this seemed more compact. Also check out its [official(?) documentation](http://www.cplusplus.com/reference/clibrary/cstring/memcpy/) – Matyas Jun 04 '11 at 21:00
  • @matyas: I got the "+1" part now. But the capacity will always stay zero, its value never gets updated, and we always resize for one element :) – vines Jun 04 '11 at 21:00
  • 1
    @matyas: ah, now I see THAT line :) – vines Jun 04 '11 at 21:02
  • @matyas:I implemented your method as following, but get a runtime error. http://ideone.com/CJift – JKase Jun 04 '11 at 21:13
  • Line 7 should be deleted - you allocate a completely new array and lose track of the old trans array . Line 8 should be put last (after 17) to make the whole thing correct. – Matyas Jun 04 '11 at 21:20
  • @matyas: Surely not like that? o: Doesn't add up in my brain at least and also ends up in a runtime error just after the cout-lines. – JKase Jun 04 '11 at 21:27
  • ok. I can not explain more in detail where you are wrong, but here is a working example with correct output: http://ideone.com/uz1mE. And you can substitute `memcpy` with your for loop and `maxTransactions*2+1` with `maxTransactions+1` – Matyas Jun 04 '11 at 21:32
  • @JKase: PS. In your implementation: did you initialize `amountTransactions` to 0 at the beginning? anyway I'm going to sleep :). Have fun! – Matyas Jun 04 '11 at 21:38
  • @matyas: Yeah, I did :) Thanks really much for your effort, buddy. I'll try to make do what you've given me and hope I'll figure it out some damn way :) – JKase Jun 04 '11 at 21:45
1

When you add an object and the array is too small you need to create a new one with the correct or larger size, copy the data, delete the old one and replace it with your new one.

Copy constructors are just like ordinary constructors only that they take an object of the same type. Do remember take care of your pointers properly when doing this.

 TransactionList(const TransactionList & o);
CptRed
  • 11
  • 1
  • Cheers CptRed. But how shouls a copy constructor be implemented? That's something I've been wondering, 'cause they surely didn't have anything about it in the course material. – JKase Jun 04 '11 at 20:58
  • @Alexandre C.: Duly noted :) Didn't get to reading that yet. Thanks buddy! – JKase Jun 04 '11 at 21:20
  • @JKase: you're welcome. The `C++-faq` tag is worth a search, there are some valuable articles for C++ students (http://stackoverflow.com/questions/tagged/c%2b%2b-faq ) – Alexandre C. Jun 04 '11 at 21:38
  • @JKase: have also a look at this one (hard to spot if you never saw the name): http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom – Alexandre C. Jun 04 '11 at 21:40
0

Now I finally managed to solve this puzzle. Turns out I wasn't paying enough attention to the fact that my Transaction-objects themselves held a dynamic array, so I finally came up with the idea of making an assign function to copy the objects. Thought I'd share my solution just in case any one has to tackle the same problem with the same limited set of tools.

This is how it ended up looking like:

   void TransactionList::add(Transaction & newTrans)

   {
    amountTransactions++;

    cout << "Adding a transaction-object to the array. amountTransactions = " << amountTransactions << endl;
    //Allocate a new array
    Transaction* tempTrans = new Transaction[amountTransactions];
    //Copy the objects with the assign-function
    for (int i = 0; i < amountTransactions - 1; i++)
            tempTrans[i].assign(trans[i]);

    //Delete the old one
    delete[] trans;

    //Set trans to point at the new one
    trans = tempTrans;

    //Add the newcomer object
    trans[amountTransactions - 1].assign(newTrans);
}

And the assign-function looks as follows:

void Transaction::assign(const Transaction & t)
{
    date = t.date;
    type = t.type;
    name = t.name;
    amount = t.amount;
    amountFriends = t.amountFriends;

    cout << "Hello assign " << amountFriends << endl;

    delete [] friends;
    if (amountFriends > 0)
    {
        friends = new string[amountFriends];

        for (int i = 0; i < amountFriends; i++)
            friends[i] = t.friends[i];
    }

    else
        friends = NULL;
}

I based my final solution on matyas' answer, so I owe you one buddy! :) Thanks also to Alexandre C. for good read!

I'm not counting out the possibility there might be some error in the code, but at least it compiles, runs and produces correct result. Feel free to point out if you find something that's not right.

JKase
  • 157
  • 2
  • 10
  • Also here's the complete program for reference: http://ideone.com/y7luk There seems to be one bug at least. If i do delete[] pers in the destructor for Personlist, the program ends in a runtime error. Turning the assignment in anyway now. Cheers and kudos to everyone who helped! (: – JKase Jun 06 '11 at 00:14