Click here to Skip to main content
15,891,607 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am new to C++11 and I came across enable_shared_from_this. I do not understand what it is trying to achieve? So I have a program that uses enable_shared_from_this.

C++
struct TestCase: enable_shared_from_this<testcase>
{
    std::shared_ptr<testcase> getptr() {
        return shared_from_this();
    }
    
    ~TestCase() { std::cout << "TestCase::~TestCase()"; }
};


int main()
{
    std::shared_ptr<testcase> obj1(new TestCase);
    std::shared_ptr<testcase> obj2 = obj1->getptr();
   // The above can be re written as below, then what is the need for shared_from_this()
  //  std::shared_ptr<testcase> obj2 = shared_ptr<testcase>(obj1);
}
My question is when I need a pointer to 'this', why not use the obj itself. Why to return a 'this' from a function of that class like using getptr() and then returning shared_from_this()????
I do not understand.

Second question, if enable_shared_from_this is NOT used, why is the dtor called twice that creates a problem, a crash!!!!

Another way I can bypass using enable_shared_from_this is like this.
Add this in class TestCase

C++
std::shared_ptr<testcase> getptr1(shared_ptr<testcase> obj) {
        return std::shared_ptr<testcase>(obj);
    }


and from main make a call this this:

C++
std::shared_ptr<testcase> bp2 = bp1->getptr1(bp1);


And done. We do not need enable_shared_from_this. Why on the earth do we need it??

What I have tried:

I have tried to google but what all I could find is what is enable_shared_from_this, why it is used. But my question is is there no other alternative to enable_shared_from_this (as I have mentioned in my question.)
Posted
Updated 30-Jun-19 0:46am
v4

Using Google, one ca easily find the answer and samples like this one: std::enable_shared_from_this - cppreference.com[^].

If you find hard to understand the documentation, then try the samples in a debugger.

Those links are also useful to understand the purpose:
enable_shared_from_this Class[^].
Safely using enable_shared_from_this | Musing Mortoray[^]
enable_shared_from_this - C++ Reference[^]
c++ - what is the usefulness of enable_shared_from_this - Stack Overflow[^]enable_shared_from_this - 1.60.0[^]

Well, in most cases you can avoid the problem by writing different code. Using enable_shared_from_this essentially allows the code to works properly in cases it would not have otherwise. By using that, it allows to find internal data used to maintain reference count.

As far as I understand, it allows member function to call other functions that uses shared_pointers as parameters.

One could probably write similar code by hand...

Update:
Here is code to explain the problem...
C++
void f(shared_pointer<A> x) { }

class A 
{
public:
  A() { }
  ~A() { std::cout << "~A" << std::endl; }
  void test() { /* How do you call f function here? */ }

private:
  A(const A&);
  A& operator=(const A&);
};

int main()
{
  shared_pointer<A> a(new A);
  a->test();
}


Make the code above work with you simple solution... If you can do it by only modifying test function and without the destructor being called twice, then at that point, it might be legitimate to wonder why the code is no complicated...

Otherwise, by using enable_shared_from_this, you can make that code works as expected.

This would essentially embed a weak shared pointer in the class so that you can create multiple shared pointers from this (that is, Something that is accessible from a member function like test above.
 
Share this answer
 
v4
Comments
Priyanka Sabharwal81 17-Mar-16 8:38am    
Thanks Philippe. But if every body understand every thing, then there would not be a question forum ever!!! The link that you had send tells how to use enable_shared_from_this and why to use it. How and why, does not answers my question. My concern is that the syntax that I wrote to bypass the use of enable_shared_from_this is not a complex one. Rather I felt that enable_shared_from_this is adding complexity. Is there any other scenario which I am missing that can only be resolved by using enable_shared_from_this and not the alternative that I wrote.
I know every problem has more than one solution, but we prefer the use of the easy one. Easy means that is more readable and easily writable.
cheers!
Philippe Mori 17-Mar-16 10:38am    
I have updated my answer to show a problematic case. If you are able to make it works properly with simpler code, then show it.

Remember that that code was written by expert...
A case when this would come in handy is 
* When there is a design guarantee that an object will always be owned by a shared pointer.
* In this case, we can blindly use shared_from_this() to return our own shared instance to another function which accepts a shared_ptr<> version of our class.

For example, 

The DBusConnection object is always shared by many instances which means that is is always passed through shared_ptr<DBUsConnection> everywhere. So in that case we can write a code snippet like this:


In the git source of CommonAPI we can see the references:

capicxx-dbus-runtime/DBusServiceRegistry.cpp at 77fd3ae09034b6f7cb87be7fd77d08cf106f53cb · GENIVI/capicxx-dbus-runtime · GitHub[^]

C++
void DBusConnection::notifyDBusSignalHandlers(DBusSignalHandlerPath handlerPath,
                                              const DBusMessage& dbusMessage,
                                              ::DBusHandlerResult& dbusHandlerResult) {

    // ensure, the registry survives
    std::shared_ptr<DBusServiceRegistry> itsRegistry_ = DBusServiceRegistry::get(shared_from_this());

    std::map<const DBusSignalHandler*,
        std::weak_ptr<DBusProxyConnection::DBusSignalHandler>> itsHandlers;
    {
        std::lock_guard<std::mutex> dbusSignalHandlersLock(signalHandlersGuard_);

        auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath);
        if(signalHandlerPathIt != dbusSignalHandlers_.end()) {
            itsHandlers = signalHandlerPathIt->second;
        }
    }



If we inspect the DBusServiceRegistry::get(..) and DBusServiceRegistry::Remove(..) static functions, we can notice that the shared pointer instance is getting added into a static registry map and removed respectively.

C++
std::shared_ptr<DBusServiceRegistry>
DBusServiceRegistry::get(std::shared_ptr<DBusProxyConnection> _connection, bool _insert) {
    std::unique_lock<std::mutex> itsGuard(registriesMutex_);
    auto registries = getRegistryMap();
    auto registryIterator = registries->find(_connection.get());
    if (registryIterator != registries->end())
        return registryIterator->second;

    std::shared_ptr<DBusServiceRegistry> registry
        = std::make_shared<DBusServiceRegistry>(_connection);
    if (registry) {
        if(_insert) {
            registries->insert( { _connection.get(), registry } );
        }
        itsGuard.unlock();
        registry->init();
    }
    return registry;
}

void
DBusServiceRegistry::remove(std::shared_ptr<DBusProxyConnection> _connection) {
    std::lock_guard<std::mutex> itsGuard(registriesMutex_);
    auto registries = getRegistryMap();
    registries->erase(_connection.get());
}


As we can see here that when the desktop bus connection is getting disconnected, we see that the instance is getting removed from the registry map.

C++
void DBusConnection::disconnect() {
    std::unique_lock<std::recursive_mutex> dbusConnectionLock(connectionGuard_);

    std::shared_ptr<DBusServiceRegistry> itsRegistry = DBusServiceRegistry::get(shared_from_this());

    isDisconnecting_ = true;

    if (std::shared_ptr<CommonAPI::MainLoopContext> mainLoopContext = mainLoopContext_.lock()) {
        DBusServiceRegistry::remove(shared_from_this());
        Factory::get()->releaseConnection(connectionId_);
}
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900