views:

71

answers:

3

I've got a method that creates some Foo and adds it to a vector of Foos. Foos are in charge of deleting their Bars during destruction. The Foo constructor takes a pointer of Bars and a size of them. When the function returns, the local Foo gets deleted and destroys its Bars, however I get a valid Foo object back.

How should I be handling this more correctly? Should I have Bars managed some other way? Should I have the constructor copy the array instead? I am potentially going to have hundreds of thousands of Bars.

Haven't tried to compile this, this is just an example of what is going on.

class Bar
{
    public:
        Bar(){}
        ~Bar(){}

        int a;
        int b;
        int c;
};

class Foo
{
    private:
        Bar * myBars;
        int size;

    public:
        Foo(Bar * myBars, int size)
        {
            this->myBars = myBars;
            this->size = size;
        }

        Bar * getBars()
        {
            return myBars;
        }

        int getSize()
        {
            return size;
        }

        ~Foo()
        {
            if(myBars != NULL)
            {
                if(size == 1)
                {
                    delete myBars;
                }
                else if(size > 1)
                {
                    delete [] myBars;
                }
            }
        }
};

void doIt(std::vector<Foo> & foos)
{
    Bar * myBars = new Bar[4];
    //Pretend we initialize the Bars...
    Foo foo(myBars);
    foos.push_back(foo);

    //local foo gets deleted
}

int main()
{
    std::vector<Foo> foos;
    doIt(foos);

    Bar * myBars = foos[0].getBars();
    int size = foos[0].getSize();

    //Do something with myBars

    return 0;
}
+1  A: 

Why not use a std::vector for Bars:

class Foo
{
    private:
        vector<Bar> myBars;

    public:
        Foo(const vector<Bar>& bars) : myBars(bars) {}

        vector<Bar>& getBars()
        {
            return myBars;
        }

        int getSize()
        {
            return myBars.size();
        }
};
Donotalo
Much better idea than mine. What was I thinking.
Martin York
@Martin, thanks.
Donotalo
A: 

Similar to Bars, you can create Foo objects also on the heap to avoid destruction in doIt functon. If Foo object is dynamically allocated, it will not be destroyed upon the return of doIt() function.

You can clean up all Foo and Bar objects at the end like below(Working code)

#include <vector>
using namespace std;
class Bar 
{ 
    public: 
        Bar(){} 
        ~Bar(){} 

        int a; 
        int b; 
        int c; 
}; 

class Foo 
{ 
    private: 
        Bar * myBars; 
        int size; 

    public: 
        Foo(Bar * myBars, int size) 
        { 
            this->myBars = myBars; 
            this->size = size; 
        } 

        Bar * getBars() 
        { 
            return myBars; 
        } 

        int getSize() 
        { 
            return size; 
        } 

        ~Foo() 
        { 
            if(myBars != NULL) 
            { 
                if(size == 1) 
                { 
                    delete myBars; 
                } 
                else if(size > 1) 
                { 
                    delete [] myBars; 
                } 
            } 
        } 
}; 

void doIt(std::vector<Foo *> & foos) 
{ 
    Bar * myBars = new Bar[4]; 
    //Pretend we initialize the Bars... 
    Foo *pFoo = new Foo(myBars, 4); 
    foos.push_back(pFoo); 
} 

int main() 
{ 
    std::vector<Foo *> foos; 
    doIt(foos); 

    Bar * myBars = foos[0]->getBars(); 
    int size = foos[0]->getSize(); 

    for(int i = 0;i < foos.size(); i++)
    {
        delete foos[i];
    }
    foos.clear();

    return 0; 
} 
bjskishore123
I like std::auto_ptr but it does not work with the standard containers. Also the code is not exception safe. If you are going to have a container with owned pointers then you should probably look at boost pointer containers. boost::ptr_vector<Foo>
Martin York
@Martin: updated.
bjskishore123
A: 

You don't show the copy constructor, and there is no appropriate default copy constructor. You also don't have a default (no argument) constructor which is often needed by the stl containers.

When you push a Foo into the vector it is creating a new Foo as a copy.

Currently you are likely to be deleting the Bar pointer twice.

Native arrays should be avoided in use with non POD types - Bar[4] won't be running the constructor on Bar for each object. Prefer the use of Vector

Greg Domjan
@Greg: Yes, It is deleting Bar pointer twice.
bjskishore123
@Greg: I realize what is happening, I was looking for The Best Way(tm) to fix it.
foobar1234
@foobar1234: Recommend getting some books, like Meyers Effective C++, Sutter Exceptional C++. "The Best Way"(tm) will not be clear without more detail on the overall structure and usage of all the Foo and Bar. For instance will you always 'for each' the containers, or need to lookup, need to add and/or remove many items etc.
Greg Domjan