7

Suppose I have a class derived from std::enable_shared_from_this

struct foo
  : std::enable_shared_from_this<foo>
{
    std::shared_ptr<foo> get_shared()
    {
        return shared_from_this();
    }

    bool is_shared() const
    {
        /* implementation ??? */
    }
};

foo  A;
auto S= A.get_shared();   // UB (pre c++17) or exception (c++17)

Prior to c++17, there appears to be no way to detect whether an object foo is actually managed by a shared_ptr. Correct?

But even for c++17, I'm not sure how to best implement such a detection. One obvious approach is

bool foo::is_shared() const
{
    try {
        shared_from_this();
    } catch(...) { 
        return false;
    }
    return true;
}

But can the try-catch be avoided? Can I use weak_from_this()? How?

Walter
  • 44,150
  • 20
  • 113
  • 196

1 Answers1

6

You can implement is_shared leveraging weak_from_this() in C++17 like:

bool is_shared() const
{
    return !weak_from_this().expired();
}

This is exception free and will only return true is the object is actually managed by a shared_ptr.

Pre C++17 there isn't a way to check since it is undefined behavior to call shared_from_this() when the object is not owned by a shared_ptr. It wasn't until weak_from_this() was introduced in C++17 that we could access the private weak_ptr member of std::enable_shared_from_this (via a copy) that we can inspect the state in a defined manner.

Arne Vogel
  • 6,346
  • 2
  • 18
  • 31
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I don't understand your argument why there is no way prior to C++17. Yes, calling `shared_from_this()` is UB, but the `weak_ptr` was there already (though I reckon that was not specified) – Walter Dec 18 '18 at 16:31
  • 2
    @Walter It's there but you can't access it. It is a private member of `std::enable_shared_from_this`. It wasn't until C++17 that we are given access to the member (via a copy). – NathanOliver Dec 18 '18 at 16:32
  • Starting from C++17, calling `shared_from_this()` is equivalent to `shared_­ptr(weak_­this)` where `weak_this` is an "exposition only" weak pointer. Also, `shared_from_this` no longer has a precondition. I take this to mean that it is now defined behavior to call `shared_from_this()` on a never-shared object, and it will throw `bad_weak_ptr` (as most implementations probably always did). – Arne Vogel Dec 18 '18 at 16:55
  • 1
    @ArneVogel Correct. It is now defined and it will throw an exception. Pre C++17 it wasn't defined and there was no way to check if you could call `shared_from_this` – NathanOliver Dec 18 '18 at 16:56