Search code examples
c++design-patternsdata-structuresclass-design

Variable-length objects: Ever a good idea?


My application uses a large amount of Panda objects. Each Panda has a list of Bamboo objects. This list does not change once the Panda is initialized (no Bamboo objects are added or removed). Currently, my class is implemented as follows:

class Panda
{
    int a;
    int b;
    int _bambooCount;
    Bamboo* _bamboo;

    Panda (int count, Bamboo* bamboo)
    {
        _bambooCount = count;
        _bamboo = new Bamboo[count];

        // ... copy bamboo into the array ...
    }
}

To alleviate the overhead of allocating an array of Bamboo objects, I could implement this class as follows -- basically, instead of creating objects via the regular constructor, a construction method allocates a single memory block to hold both the Panda object and its Bamboo array:

class Panda
{
    int a;
    int b;

    Panda ()
    {
        // ... other initializations here ...
    }

    static Panda *createPanda (int count, Bamboo* bamboo)
    {
        byte* p = new byte[sizeof(Panda) +
                           sizeof(Bamboo) * count];
        new (p) Panda ();

        Bamboo* bamboo = (Bamboo*)
            p + sizeof(Panda);

        // ... copy bamboo objects into the memory
        // behind the object...

        return (Panda*)p; 
    }
}

Can you foresee any problems with the second design, other than the increased maintenance effort? Is this an acceptable design pattern, or simply a premature optimization that could come back to bite me later?


Solution

  • C++ gives you another option. You should consider using std::vector.

    class Panda
    {
        int a;
        int b;
        std::vector<Bamboo> bamboo;
        // if you do not want to store by value:
        //std::vector< shared_ptr<Bamboo> > bamboo;
    
        Panda (int count, Bamboo* bamb) : bamboo( bamb, bamb+count ) {}
    }
    

    If you want to store Panda and Bamboos in continuous memory you could use solution from this article. The main idea is to overload operator new and operator delete.