Does the standard mandate enable_shared_from_this is to be inherited publicly? Why?
Asked Answered
Y

1

7

It's common to inherit from enable_shared_from_this just to be able to return shared_ptr's from member functions as the primary intention, with no intention of exposing enable_shared_from_this API in the derived class.

Since to make use of enable_shared_from_this one must do so through public inheritance (does the standard mandates this? what's the rationale?), this can't be achieved and enable_shared_from_this API is forced into derived class public API.

Inherenting enable_shared_from_this privately and making shared_ptr a friend class do work on clang coupled with libc++, but doesn't work with stdlibc++.

Since private enable_shared_from_this + friend shared_ptr (or protected inheritance) seems to cover this use case, shouldn't it be sufficient by the standard for fitting as a solution for the "shared from this" problem?

Yakut answered 3/7, 2016 at 1:17 Comment(7)
You could try inheriting protected, i.e. class T : protected std::enable_shared_from_this<T> { ... }; ? I didn't try it myselfHulburt
@ChrisBeck ok thanks. I guess the question still holds though, if one doesn't wish to do even that (protected).Yakut
I think that there's no way the shared_from_this mechanism can work if the inheritance is totally private. The way it works, if I understand right, is that the control structure for the shared_ptr (the reference count) is stored in a prefix in your class, so like, there is some data member in std::enable_shared_from_this<T>. In order to make a shared_ptr from this, it needs to be able to static cast this and find the ref counter. Also std::make_shared need to be able to detect things like this in your type. If the inheritance is private then I guess they can't do that. Not sure..Hulburt
@ChrisBeck that's the reason I mention being friend of std::shared_ptr.Yakut
Ok, but then you might need to friend std::make_shared and std::weak_ptr and other things potentiallyHulburt
You know, this is a pretty good question, I guess I don't see a good reason that shared_from_this() is not standardized as a protected member of std::enable_shared_from_this. Then if you want to expose it publicly you can put a using declaration. That's easier than all this friend stuff.Hulburt
@ChrisBeck good. For me it's a better design but it would be a breaking change applied now :-/Yakut
L
3

Since private enable_shared_from_this + friend shared_ptr seems to cover this use case, shouldn't it be sufficient by the standard?

No. The standard permits implementations wide latitude with how they implement things. The constructor of shared_ptr<T> that adopts an object may defer the shared-from-this stuff to some helper function or other object. For maximum irony, it could defer to a base class of shared_ptr<T> ;)

As such, enable_shared_from_this must be accessible by any code in order for the shared_ptr constructor to work.

Locate answered 3/7, 2016 at 2:16 Comment(6)
Looks like a tradeoff, allowing wide latitude implementations in detriment of every user's public API vs constraining it lightly for sake of the user API optionsYakut
@pepper_chico: You'll have to get in line behind everyone trying to get function pointers/member pointers to standard library functions.Locate
So, why doesn't enable_shared_from_this<T> force that it's a public base class of T, that is, T* is convertible to enable_shared_from_this<T>*? I could imagine a compile-time error when that fails..Malcolm
@lorro: Because you can't actually do that. At the time when enable_shared_from_this<T> is being instantiated with a particular T, that particular T is incomplete. After all, T is derived from enable_shared_from_this<T>, right? So when this is being instantiated, the only thing the compiler knows about T is that the name exists. The member functions of enable_shared_from_this can access T's definition because of how C++ specifies how inline member functions work. But those rules only work for members; you can't static_assert on a property of T in the class itself.Locate
@NicolBolas: ideone.com/cpzAhH : remove comments around private to see the error msg.Malcolm
@NicolBolas Note that an incomplete class type can still be a derived type: in the definition of the derived class, it is already a derived type during the definition of members.Rotunda

© 2022 - 2024 — McMap. All rights reserved.