I have a class (Geometry
) that implements an interface (LinkList
). The code at the bottom of my example is obviously wrong, so I'm looking at implementing std::enable_shared_from_this
. Can Geometry
safely inherit from std::enable_shared_from_this<LinkList>
and can I safely change the getLinkList()
method to shared_from_this()
? What happens if my Geometry
class has multiple interfaces that it inherits, can I do this for all of the interfaces?
class Link
{
public:
std::string getName() { return "the name"; }
};
class LinkList
{
public:
virtual Link* getLink(int id) = 0;
virtual int size() = 0;
};
class Geometry : LinkList
{
private:
int state;
public:
void doSomething() { state = 1; }
virtual Link* getLink(int id) { return new Link(); }
virtual int size() { return 1; }
std::shared_ptr<LinkList> getLinkList() { return std::shared_ptr<LinkList>(this); }
};
void printList(std::shared_ptr<LinkList> linkList)
{
for (int i = 0; i < linkList->size(); i++)
{
std::cout << linkList->getLink(i)->getName() << std::endl;
}
}
void main()
{
Geometry* geom = new Geometry();
printList(geom->getLinkList());
geom->doSomething(); // Error here
}
The code at the bottom of my example is obviously wrong
The code there is not obviously wrong, the bug is in getLinkedList
which gives ownership of this
to a shared_ptr
causing it to be deleted when the printList
returns and the last shared_ptr object goes out of scope. So the last line of the example is rather non-obviously wrong, because the previous line subtly deleted the object.
Can
Geometry
safely inherit fromstd::enable_shared_from_this<LinkList>
Yes, it's just a base class. It's nearly always safe to inherit from it (that doesn't mean you can use it safely though!)
and can I safely change the
getLinkList()
method toshared_from_this()
?
Only if the Geometry
object is owned by a shared_ptr
, and in your code it isn't:
Geometry* geom = new Geometry();
You need to store the pointer in a shared_ptr
(preferably immediately when you create it) for the enable_shared_from_this
base class to be usable, so this should be OK:
auto geom = std::make_shared<Geometry>();
printList(geom->shared_from_this());
geom->doSomething();
(Of course using shared_from_this()
is pretty pointless there, because you already have the sahred_ptr anyway and could just do printList(geom)
).
What happens if my
Geometry
class has multiple interfaces that it inherits, can I do this for all of the interfaces?
No, if the class has multiple enable_shared_from_this
base classes then the shared_ptr
constructors won't know which one to initialize. I think you'll get an error due to ambiguity, or if not the enable_shared_from_this
base classes will all hold an empty weak_ptr
making them useless.
Update:
You could make Geometry
derive from enable_shared_from_this<Geometry>
(not from enable_shared_from_this<LinkList>
and not from every interface), and define:
shared_ptr<LinkList> Geometry::getLinkList()
{
return shared_from_this();
}
The object returned by shared_from_this()
will convert implicitly to shared_ptr<LinkList>
. You still need this
to be owned by a shared_ptr
in the first place though.