I am currently trying to learn how to use smart pointers. However while doing some experiments I discovered the following situation for which I could not find a satifying so
You have several problems in you design, that seem to stem from you misunderstanding of smart pointers.
Smart pointers are used to declare ownership. You are breaking this by declaring that both the parents owns all children, but also that each child own it's parent. Both can't be true.
Also, you are returning a weak pointer in getChild()
. By doing so, you are declaring that the caller shouldn't care about the ownership. Now this can be very limiting, but also by doing so, you must make sure that the child in question won't get destroyed while any weak pointers are still held, if you would use a smart pointer, it would get sorted out by itself.
And the final thing. Usually, when you are accepting new entities, you should usually accept raw pointers. Smart pointer can have their own meaning for swapping children between parents, but for general usage, you should accept raw pointers.
There is std::enable_shared_from_this just for this purpose. You inherit from it and you can call .shared_from_this() from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr. So your code might look like this (assuming children rely on existence of parent and not the other way around):
class A;
class B;
class A
: public std::enable_shared_from_this<A>
{
public:
void addChild(std::shared_ptr<B> child)
{
children.push_back(child);
// like this
child->setParent(shared_from_this()); // ok
// ^^^^^^^^^^^^^^^^^^
}
private:
// note weak_ptr
std::list<std::weak_ptr<B>> children;
// ^^^^^^^^
};
class B
{
public:
void setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
}
private:
std::shared_ptr<A> parent;
};
Note however, that calling .shared_from_this()
requires that this
is owned by std::shared_ptr
at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this()
from within a constructor or destructor.