I have a questing around such staff.
There is a class A which has a object of type class B as it’s member. Since I’d like B to be a base class of group of other classes I need to use pointer or reference to the object, not it’s copy, to use virtual methods of B inside A properly. But when I write such code
class B
{public:
B(int _i = 1): i(_i) {};
~B()
{i = 0; // just to indicate existence of problem: here maybe something more dangerous, like delete [] operator, as well!
cout << "B destructed!\n";
};
virtual int GetI () const {return i;}; // for example
protected:
int i;
};
class A
{public:
A(const B& _b): b(_b) {}
void ShowI () {cout <<b.GetI()<<'\n';};
private:
const B& b;
};
and use it this way
B b(1);
A a(b);
a.ShowI();
it works perfectly:
1
B destructed!
But
A a(B(1));
a.ShowI();
give very unwanted result: object b creates and a.b is set as reference to it, but just after constructor of A finished, object b destructs! The output is:
B destructed!
0
I repeat again, that using copy of instead of reference to b in A
class A
{public:
A(B _b): b(_b) {}
void ShowI () {cout <<b.GetI()<<'\n';};
private:
B b;
};
won’t work if B is base class and A calls it’s virtual function. Maybe I’m too stupid since I do not know not know proper way to write necessary code to make it works perfectly (then I’m sorry!) or maybe it is not so easy at all 🙁
Of course, if B(1) was sent to function or method, not class constructor, it worked perfect. And of course, I may use the same code as in this problem as described here to create B as properly cloneable base or derived object, but doesn’t it appears too hard to for such easy looking problem? And what if I want to use class B that I could not edit?
This is a standard issue, don’t fear.
First, you could retain your design with a subtle change:
By using a reference instead of a const reference, the compiler will reject the call to A’s constructor that is made with a temporary because it is illegal to take a reference from a temporary.
There is no (direct) solution to actually retain the
const, since unfortunately compilers accept the strange construct&B()even though it means taking the address of a temporary (and they don’t even shy to make it a pointer to non-const…).There are a number of so-called smart pointers. The basic one, in the STL is called
std::auto_ptr. Another (well-known) one is theboost::shared_ptr.Those pointers are said to be smart because they allow you no to worry (too much) about the destruction of the object, and in fact guarantee you that it WILL be destroyed, and correctly at that. Thus you never have to worry about the call to
delete.One caveat though: don’t use
std::auto_ptr. It’s a mean beast because it has a unnatural behavior regarding copying.The problem is that copying (using copy construction) or assigning (using assignment operator) means transfer of ownership from the copied toward the copying… VERY SURPRISING.
If you have access to the upcoming standard, you can use
std::unique_ptr, much like an auto pointer except from the bad behavior: it cannot be copied or assigned.In the mean time, you can simply use a
boost::shared_ptror perhapsstd::tr1::shared_ptr. They are somewhat identical.They are a fine example of “reference counted” pointers. And they are smart at that.
That’s what reference counted means: a copy and its original point to the same instance, and they share its ownership. And as long as there is one of them still alive, the instance of A exists, being destructed by the last one of them to die so you don’t have to worry about it!!
You should remember though, that they do share the pointer. If you modify the object using one shared_ptr, all its relatives will actually see the change. You can do a copy in the usual mode with pointers:
So to sum up:
auto_ptr, you’ll have bad surprisesunique_ptrif available, it’s your safer bet and the easiest to deal withshare_ptrotherwise, but beware of the shallow copy semanticsGood luck!