finiteloop finiteloop - 3 months ago 18
C++ Question

Array as private member of class

I am trying to create a class which has a private member that is an array. I do not know the size of the array and will not until the value is passed into the constructor. What is the best way to go about defining the class constructor as well as the definition in the .h file to allow for this variable size of the array?

Answer

If you want a "real" C-style array, you have to add a pointer private member to your class, and allocate dynamically the memory for it in the constructor (with new). Obviously you must not forget to free it in the destructor.

class YourClass
{
  private:
    int * array;
    size_t size;

    // Private copy constructor/assignment operator to block copying of the object, see later
    YourClass(const YourClass & Other) {}
    YourClass& operator=(const YourClass& Other) {}

  public:
    YourClass(size_t Size) : array(new int[Size]), size(Size)
    {
        // do extra init stuff here
    };

    ~YourClass()
    {
        delete [] array;
    }
};

To make this work easier, you may consider to use a smart pointer (for example, a boost::scoped_array), that you may initialize using the initializer list before the constructor or simply in the constructor.

class YourClass
{
  private:
    boost::scoped_array<int> array;
    size_t size;
  public:
    YourClass(size_t Size) : array(new int[Size]), size(Size)
    {
        // do extra init stuff here
    }

    // No need for a destructor, the scoped_array does the magic
};

Both these solutions produce noncopyable objects (you didn't specify if they had to be copyable and their copy semantic); if the class don't have to be copied (which happens most of times), these both are ok, and the compiler will generate an error if you try to copy/assign one class to another, in the first case because the default copy constructor and assignment operator have been overloaded with private ones, in the second case because boost::scoped_array is noncopiable.
If, instead, you want to have copyable objects, then you must decide if you want to create a copy that shares the array (so, just a pointer copy) or if you want to create a new, separate array for the other object. In the first case, you must be very careful before freeing the allocated memory, since other objects may be using it; a reference-counter is the most common solution. You can be helped in this by boost::shared_array, which does all the tracking work automatically for you.
If instead you want to do a "deep copy", you'll have to allocate the new memory and copy all the objects of the source array to the target array. In the operator= you have to remember to free the old array of the destination object (Other in the code). Moreover, in operator= you must also take extra care to check if &Other == this, and, in this case, avoid the copy.

Still, the simplest solution is to use a std::vector as a private member: it would handle all the allocation/deallocation stuff by itself, constructing/destroying itself correctly when the object of your class is constructed/destructed. Moreover, it implements the deep-copy semantic out of the box. If you need to make your callers access the vector read-only, then, you could write a getter that returns a const_iterator or a const reference to the vector object.