views:

418

answers:

4

I'm a bit confused about handling an array of objects in C++, as I can't seem to find information about how they are passed around (reference or value) and how they are stored in an array.

I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?

In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space. I try to create a dynamic array of myClass objects within a myContainer. In the myContainer.addObject() method I attempt to make a bigger array, copy all the objects into it along with a new object, then delete the old one. I'm not at all confident that I'm cleaning up my memory properly with my destructors - what improvements could I make in this area?

class myClass
{
    private:
          string myName;
          unsigned short myAmount;

    public:
        myClass(string name, unsigned short amount)
        {
            myName = name;
        myAmount = amount;
        }

    //Do I need a destructor here? I don't think so because I don't do any
    // dynamic memory allocation within this class
};



class myContainer
{
    int numObjects;
    myClass * myObjects;

   public:
    myContainer()
    {
        numObjects = 0;
    }   

    ~myContainer()
    {
        //Is this sufficient?
        //Or do I need to iterate through myObjects and delete each
        // individually?
        delete [] myObjects;
    }


    void addObject(string name, unsigned short amount)
    {
        myClass newObject = new myClass(name, amount);

        myClass * tempObjects;
        tempObjects = new myClass[numObjects+1];
        for (int i=0; i<numObjects; i++)
            tempObjects[i] = myObjects[i]);
        tempObjects[numObjects] = newObject;
        numObjects++;
        delete newObject;

        //Will this delete all my objects? I think it won't.
        //I'm just trying to delete the old array, and have the new array hold
        // all the objects plus the new object.
        delete [] myObjects;
        myObjects = tempObjects;
    }
};
+3  A: 

No, a dynamic array is not an array of pointers to that type - its a pointer to the first element. The elements are laid out consecutively in memory and are destroyed when the array is delete[]ed.

Thus your deallocation looks fine - you create dynamic arrays of myClass objects so you don't have to delete them individually. You would only have to do this if you had an array of pointers to (dynamically allocated) objects.

There are two definitive errors though:

tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance?

This should be e.g.:

tempObjects[numObjects] = myClass(name, amount);

Also, myObjects is never initialized, which means it contains garbage and dereferencing/using it leads to undefined behaviour.

Finally, unless you are doing this for learning purposes, simply use containers like std::vector that do all the work for you already.

Georg Fritzsche
Thanks very much for the response, I hadn't considered the pointer/instance disparity there.I stripped my code down and changed the names for intelligibility - the real version has some logic to prevent accessing myObjects - I forgot to add a comment to say I'd removed this (I have an int that keeps track of how many myClass objects there are in the array)It's for an assignment and they've specified that we must use dynamic arrays for our dynamic memory management (rather than utility classes). I will liik at std::vector for future reference though.
Dr. Monkey
I would vote you up, but it appears I've not yet earned enough (or any) reputation.
Dr. Monkey
Good to hear it helped. For future questions: if you mention such academic restrictions we often can provide better help.
Georg Fritzsche
A: 

Try to test it, to see what happens (yes, that may be compiler-specific, but still)... You could try to add a custom destructor to myClass (even though you don't need one), that increments a "global" counter when called, Then print the counter after deleting the array.

I would expect the destructor of each object to be called. Note that quite often objects are stored "by-pointers" to allow for inherited objects to be put into the array (avoiding "slicing").

S.C. Madsen
Actually I will have two subclasses with different types of data in them to store in an array in a later part of this assignment, so that's quite helpful.In this case myClass is just a utility class contained fully within myContainer and it will never be extended, so I think a value array is more appropriate than a pointer array. I assume that there would be extra overhead associated with following the pointers, and the extra memory required to store the pointers themselves (this is a small project for an assignment and performance is not an issue - I still like to consider it).
Dr. Monkey
+1  A: 

I would expect an array of objects to be an array of pointers to that object type, but I haven't found this written anywhere. Would they be pointers, or would the objects themselves be laid out in memory in an array?

The array will consist of the objects themselves. If you want to have an array of pointer you will have to declare that:

myClass ** tempObjects;  
tempObjects = new myClass*[numObjects+1];  

I assume you are used to C# or Java? In those languages objects can only be allocated on heap and are always accessed by referenced. It is possible in C++, but in C++ you can also put objects directly on the stack, or directly construct an array of the objects themselves.

In the example below, a custom class myClass holds a string (would this make it of variable size, or does the string object hold a pointer to a string and therefore take up a consistent amount of space?

Number two: The string object itself is constant in size, but has a pointer to a dynamically sized buffer allocated from the heap.

I think the deallocation looks fine. The code could be written more efficient in various ways, but it looks correct.

Anders Abel
Thanks for the response. I cut the code down somewhat for conciseness, and am aiming more for clarity than efficiency as it is just a small assignment.I guess since any object that requires a variable amount of memory cannot use statically allocated memory for this, it would have to work like the string class and use a pointer to dynamically allocated memory. As long as such classes encapsulate the deallocation of this memory in their destructors, I should be able to use them as though they are any other class with fixed field sizes (performance concerns aside).
Dr. Monkey
+3  A: 

An array in C++ is an array of objects laid out in memory. So for example in:

struct pair {
   int x; int y;
};
...
pair array[10];

Each item in the array is going to be with a size of two ints. If you want an array of pointers you can simply declare one:

pair* array_of_pointers[10];

The string objects have pointers to the variable size part of the string. So they're safe. In fact they're the important lesson here. Same way you use the string class to avoid excessive memory handling you can use the vector class to avoid all the troubles of handling a dynamic array.

For the case you're doing this as an exercise. Here are a few problems: newObject needs to be allocated locally, without new. This will make the code correct (as newObject is not a pointer and new returns a pointer) and will also save you the trouble of explicitly handling memory. (On a more advanced note, this makes the code exception safe in one more location) myObject is never initialized. And you don't use initialization lists in the constructor. The constructor should look like this:

myContainer() : numObjects(0), myObjects(NULL)
{

}  

The destructors in the code are exactly as they should be.

Shiroko
Thanks, that's exactly what I was after, and I hadn't considered initialising myObjects to NULL (my real code has logic to prevent myObjects being accessed if numObjects is 0, but I took this out to improve inteligibility and forgot to add a comment to say I'd done so)I have only used structs in C#. Is there any significant difference between structs in C# and C++?
Dr. Monkey
Yes.struct in C++ is like a class but everything is `public` until said otherwise. (While in a class the default is `private`)Some people tend to use the word `struct` in C++ when defining very small and simple datatypes.In C# those two have a bigger difference.A `struct` cannot be inherited and is passed by value (Unlike regular classes). There are probably a few more differences that I forgot. Basically you use them in C# for simple and small objects for performance reasons (A good example will be short vectors for graphic purpose).
Shiroko
Your syntax is wrong, it should be `pair array[10];` and `pair *array_of_pointers[10];`.
FredOverflow
Whoopsy, oh well :)
Shiroko
Why not edit your answer if something isn't right?
Georg Fritzsche