// Untested code, I hope I didn't miss anything
class Foo {
public:
Foo(const Bar& b) : b(new Bar(b)) {}
Foo(const Foo& f) : b(new Bar(*(f.b))) {}
Foo& operator=(const Foo& f) { b = new Bar(*(f.b));
return *this; }
~Foo()throw() { delete b; }
// other methods
private:
Bar* b;
}
std::auto_ptr<> let you keep your default destructor: class Foo {
public:
Foo(const Bar& b) : b(new Bar(b)) {}
Foo(const Foo& f) : b(new Bar(*(f.b))) {}
Foo& operator=(const Foo& f) { b = new Bar(*(f.b));
return *this; }
// default destructor
// other methods
private:
std::auto_ptr<Bar> b;
}
Or you could do away with pointers altogether (not always applicable, and it may fill up your stack too): class Foo {
public:
Foo(const Bar& b) : b(b) {}
// default copy constructor, operator=, and destructor
// other methods
private:
Bar b;
}
So, whenever you need another instance of Foo, it will create another instance of Bar, which may create another instance of Baz… you get the idea. It is quite simple to do, and guarantees the absence of memory leaks, even in the presence of exceptions. But it copies a lot of data. C++ 0x move semantics will make it a little better, but it won't completely eliminate the problem.Actually, copy is the essence of RAII. Rather than saying "hey, your piece of data is interesting, let me hook it" and later complain when the fish broke your line (dangling pointer), RAII says instead "hey, your piece of data is interesting, let me have a copy" so you are sure to keep your data safe, and the other is sure to be able to safely destroy its own copy at any time.
On a side note, you could avoid copying Bar instances by using Boost's shared pointers or a garbage collector. But it will only be practical if Bar is immutable. I am also told that there are other memory management schemes, which can be very efficient, but tend to be complex and error prone.