From: Goran on
On Jul 15, 2:03 pm, dailos <dailos.guerr...(a)gmail.com> wrote:
> Hi all,
> I am struggling with a design problem. It showed up because of some
> architectures constraints.
> I have a group of classes which derive from an abstract one.
> I have a vector with pointers to the generic abstract class (neither
> vector of references nor vector of classes are allowed since it's
> abstract).
> A member function that loads objects into the vector, lets say from
> file, has to do it creating object with new operator since it couldn't
> be done by references to objects created locally.
> A public functions lets the user to add single objects too but it
> could use new or reference as an argument.
> The problem is when I need to call the destructor, and erase all of
> the objects created within the vector.
> I thought of using delete operator for each element in the vector, but
> what if some other elements has been added from a reference. delete
> &something ## failure.
>
> I guess there is no way to distinguish between object address created
> with new and created with a reference.
> How a to write a proper destructor then??

This problem of your crops up here in various forms, but does it
regularly.

There is no other good solution to your problem but to take care of
the lifetime of your objects yourself. This is because C++, just like
C, are languages where you manage heap manually. If you browse through
here, you might find some "solutions", but they are all non-standard,
wrong, of limited use, or a combination thereof.

In your main(), lifetime of theOrange is the block ({}) created by
main. You don't do anything about it, language runtime destroys it
when block is done. Lifetime of objects created in loadFruits is
whatever you decide, because these are on the heap, and you have to
manage heap manually. You have to delete them once you won't ever try
to use them again.

Now, as to what could work... You could declare addFruit like this:

void addFruit(auto_ptr<Fruit> p);

Given what auto_ptr does, it's clear that you can only addFruit
allocated on the heap. So you can take pointer out of "p" and put it
in Basket, and Basket is the owner of it's fruits (meaning, when
Basket is destroyed, all it's fruit is deleted).

That's not unreasonable lifetime handling strategy.

You could make it more complicated (warning: compiled with head-
debugger, debugged with head-debugger and tested with head-test-
suite):

class FruitHolder
{
public:
FruitHolder(Fruit& f) : _owns(false), _f(&f) {}
FruitHolder(Fruit* f) : _owns(true), _f(f) {}
FruitHolder() : _owns(false), _f(NULL) {} // standard containers
need this
FruitFolder& operator=(FruitFolder& rhs)
{
if (this == &rhs) return rhs;
if (_owns) delete _f;
_f = rhs._f;
if (rhs._owns)
{
_owns = true;
rhs._owns = false;
}
}
~FruitHolder() { if (_owns) delete f; }

operator Fruit*() { return _f; }
operator const Fruit*() const { return _f; }

private:
bool _owns; // Perhaps "mutable" and operator=(const FruitFolder&
rhs)?
Fruit* _f;
FruitHolder(const FruitHolder&); // Not needed and potentially
harmful.
};
vector<FruitHolder> fruitList;

void addFruit(auto_ptr<Fruit> p)
{
FruitHolder fh(p.release());
fruitList.push_back(f);
}
void addFruit(Fruit& f)
{
FriutHolder fh(f);
fruitList.push_back(fh);
}

Idea here is that whatever comes in as a reference is not owned by
Basket, all else is owned by basket. Fruit Holder is similar to
auto_ptr in a sense that it "moves" Fruit pointers around on
assignment (provided that my op= up here works), but it doesn't
necessarily delete them (_owns flag).

I'd be surprised if there wasn't a template library that does the
above already (Loki, perhaps? Boost?).

All in all, there you have two ( perhaps working ;-) ) solutions. None
of them are generic, but I am adamant that a generic one doesn't
exist.

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thiago A. on
> I have a group of classes which derive from an abstract one.
> I have a vector with pointers to the generic abstract class (neither
> vector of references nor vector of classes are allowed since it's
> abstract).
> A member function that loads objects into the vector, lets say from
> file, has to do it creating object with new operator since it couldn't
> be done by references to objects created locally.
> A public functions lets the user to add single objects too but it
> could use new or reference as an argument.
> The problem is when I need to call the destructor, and erase all of
> the objects created within the vector.

I did myself the same question when I was making a "Dialog/Form" class
and I could have static or dynamic buttons inside this form.

Suggestions:

1) Use only dynamic objects (always using new, smart pointers)

2) Use a pair<bool, Object*> do say when the object needs to be
deleted. You can create the "true" pair with Add(object*) and the
"false" pair with Add(Object&).

3) Create a separate list/concept for the heap objects.

The solution 2 is not perfect and it depends of the Add rule
convention.
The solution 1 and 3 are not always desirable as well.


----
http://www.thradams.com/


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: red floyd on
On Jul 15, 5:03 am, dailos <dailos.guerr...(a)gmail.com> wrote:
> Hi all,
> I am struggling with a design problem. It showed up because of some
> architectures constraints.
> I have a group of classes which derive from an abstract one.
> I have a vector with pointers to the generic abstract class (neither
> vector of references nor vector of classes are allowed since it's
> abstract).
> A member function that loads objects into the vector, lets say from
> file, has to do it creating object with new operator since it couldn't
> be done by references to objects created locally.
> A public functions lets the user to add single objects too but it
> could use new or reference as an argument.
> The problem is when I need to call the destructor, and erase all of
> the objects created within the vector.
> I thought of using delete operator for each element in the vector, but
> what if some other elements has been added from a reference. delete
> &something ## failure.
>
> I guess there is no way to distinguish between object address created
> with new and created with a reference.
> How a to write a proper destructor then??

Don't store pointers. Or else only store dynamically allocated
pointers.



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: MaksimKneller on
On Jul 15, 8:03 am, dailos <dailos.guerr...(a)gmail.com> wrote:
> I guess there is no way to distinguish between object address created
> with new and created with a reference.
> How a to write a proper destructor then??

1. a container of references can't be created, only containers of
pointers, so that makes your problem easier
2. yes you will need to delete the vector of fruit pointers to avoid
mem leak
3. make Fruit base class have a virtual destructor, that way when it
goes out of scope the destruct logic will propagate to each derived
class
4. make Basket destructor delete the mem of each Fruit pointer, then
clear the vector itself
5. FYI, using Boost shared_ptr instead to hold the Fruit pointers will
help avoid mem leak if exception is thrown after creating the
container and before calling deletes

Example code below:

class Fruit
{
public:
virtual string name() = 0;
virtual ~Fruit() {};
};


class Orange : public Fruit
{
public:
virtual string name(){return string("Orange");};
~Orange() { cout << "Deleting Orange\n"; }

};


class Watermelon : public Fruit
{
public:
virtual string name(){return string("Watermelon");};
~Watermelon() { cout << "Deleting Watermelon\n"; }

};


class Apple : public Fruit
{
public:
virtual string name(){return string("Apple");};
~Apple() { cout << "Deleting Apple\n"; };

};


class Basket
{
public:

~Basket() {
cout << "Bakset Destructor\n";

// this loop can be avoided if you use Boost's shared_ptr
to hold the elements instead of regular
// pointers as they will auto delete themselves, but
deleting these pointers still needs to be
// done either way.
for(vector<Fruit*>::iterator i = fruitList.begin(); i !=
fruitList.end(); i++)
{ delete *i; }

fruitList.clear(); // without this the size will still be 3

cout << fruitList.size();

}

void addFruit(Fruit* pFruit);
private:
vector<Fruit*> fruitList;


};


void Basket::addFruit(Fruit* pFruit)
{
fruitList.push_back(pFruit);
}

int main()
{
Basket myBasket;
myBasket.addFruit(new Watermelon());
myBasket.addFruit(new Orange());
myBasket.addFruit(new Apple());

return 0;
}

-----------------------------
Bakset Destructor
Deleting Watermelon
Deleting Orange
Deleting Apple
0


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]