Reputation: 36689
Imagine the following classes in java or C#:
class A
{
B b;
//some other stuff
public A(B b) {this.b = b;}
}
class B
{
A createA() {return new A(this); }
}
then we would use it e.g.
A complicatedCreateA()
{
B = new B();
return b.createA();
}
and the virtual machine / CLR would make sure we don't leak memory.
How can I implement a similar pattern in C++ so that I don't leak memory and reference cleaned resources?
EDIT: To make it more clear I am specifically worried about what happens if I call createA() more than once, and when the different objects A will have different lifetimes, e.g.:
A anotherMethod()
{
B = new B();
A a = b.createA();
//use a locally, or use with yet another object C, etc.
return b.createA();
}
I have the basic understanding how smart pointers work in C++. However, even if I do something like:
boost::shared_ptr<B> b(new B());
then I don't have access to this smart pointer from within B, so I can't pass it to A. And how otherwise A can make sure that the corresponding object B gets deleted not too late and not too early?
Upvotes: 1
Views: 158
Reputation: 31455
It is not a simple case of saying "use smart pointers". B appears to be a factory of A. A has a pointer to the factory object that created it (and presumably can create more A-type objects from it).
If you want B to be reference-counted it has to be "intrusively" reference counted. This is usually done with some kind of addRef() / release() mechanism, and when release() is called the last time it usually performs a delete this
I might also assume that A is polymorphic in some way such that you can get an object to create more objects of its own type (not necessarily clones) through its abstract factory.
The question is, where did the first B come from that created the first A? Do you have a lot of these B objects and do you really want to get rid of it the moment your last A is deleted, or is its lifetime managed elsewhere.
With regards to the A, your B would create a new one with regular new, and then you would put it into a shared_ptr or whatever yourself.
Note that you could use a reference here, thus:
class A
{
private:
friend class B;
explicit A( B const& b );
B (const) & b_;
A(const A&); // not implemented
public:
A* createNew() const;
~A();
};
A::A( B const& b )
: b_( b )
{
b_.addRef(); // possibly, if reference counted
}
A::~A()
{
b_.release();
}
A* A::createNew() const
{
return b_.createA();
}
for B
A* B::createNew() const
{
return new A(*this); // addRef() will be invoked
}
void B::addRef() const
{
atomically_increment( &my_refCount );
}
void B::release() const
{
if( !atomically_decrement( &my_refCount ) )
delete this;
}
where B has a mutable my_refCount of the type that fits into the atomic increment/decrement call for your system.
Note that you can use boost shared_ptr for B too but will need to need to derive B from boost::enable_shared_from_this<B>
. This is also "intrusive" but will do a lot of the work for you. Your A will now need to store a boost::shared_ptr<B>
and B::createA() will call shared_from_this()
.
To do it this way, you will need to create your first B and put it into a shared_ptr to create the first A.
Upvotes: 1
Reputation: 92381
To make it more clear I am specifically worried about what happens if I call createA() more than once, and when the different objects A will have different lifetimes, e.g.:
A anotherMethod() {
B b = new B();
A a = b.createA(); //use a locally, or use with yet another object C, etc.
return b.createA();
}
There is no need at all to create objects with new B();
, you can just create them on the stack and their lifetimes will be handled automatically.
Just do it like this:
A anotherMethod() {
B b;
A a = b.createA(); //use a locally, or use with yet another object C, etc.
return b.createA();
}
Unlike in some other languages, this is not references to heap objects but values that are copied. The copies will be destroyed when their respective lifetime is over. Automatically!
Upvotes: 0
Reputation: 254751
The exact equivalent gets a little bit complicated:
class A
{
std::shared_ptr<B> b;
//some other stuff
public:
A(std::shared_ptr<B> const & b) : b(b) {}
};
class B : public std::enable_shared_from_this<B>
{
public:
A createA() {return A(shared_from_this());}
};
A complicatedCreateA()
{
std::shared_ptr<B> b = std::make_shared<B>();
return b->createA();
}
Alternatively, you could avoid the shared_from_this
malarkey by making createA
a non-member (or static member, if it needs access to B
s privates), taking a shared pointer argument:
A createA(std::shared_ptr<B> const & b) {return A(b);}
A complicatedCreateA()
{
std::shared_ptr<B> b = std::make_shared<B>();
return createA(b);
}
Upvotes: 3
Reputation: 75150
Either allocate them only on the stack (preferable) or (for times when you can't) use smart pointers, which obviate the need for manual memory management and are exception-safe when used properly.
class B;
class A
{
public:
std::unique_ptr<B> b;
A(B b) : b(make_unique<B>(b)) { }
};
class B
{
public:
std::unique_ptr<A> createA() { return make_unique<A>(*this); }
};
Then
std::unique_ptr<A> complicatedCreateA()
{
B b; // or std::unique_ptr<B> bptr(make_unique<B>()); but here that's useless more work
return b.createA();
}
And you don't need to call delete
on the return value of createA
or on the member A::b
because whenever the unique_ptr
s go out of scope, they will clean up the A*
and B*
they own.
Notice that you call make_unique<T>
to make a unique_ptr
. This has the advantage of being more exception-safe than plain new
, though you can use that too, like : b(new B(b))
and return std::unique_ptr<A>(new A(*this));
.
There is also the reference-counted shared_ptr
for when you need to have multiple pointers to the same object.
Upvotes: 3
Reputation: 5947
If you have access to boost, you can use smart pointers. Depend what you want to achieve, you can either use boost::shared_ptr
(reference counting one) or boost::scoped_ptr
.
Have a look at: http://www.boost.org/doc/libs/1_48_0/libs/smart_ptr/smart_ptr.htm
Upvotes: 0