6

I'm learning smart pointers and shared_from_this. In Class Inheritance Relations, it will be very hard to understand.

I have two base classes CA and CB, they are derived from enable_shared_from_this, and the child class CC derives from both CA and CB. I want to take out of the three classes shared pointer from the class self, so I write the sharedCAfromThis, sharedCBfromThis and sharedCCfromthis.

class CA  : private enable_shared_from_this<CA> {
public:
    shared_ptr<CA> sharedCAfromThis() { return shared_from_this();  }
    virtual ~CA() {};
    void print() {
        cout << "CA" << endl;
    }
};

class CB : private enable_shared_from_this<CB> {
public:
    shared_ptr<CB> sharedCBfromThis() { return shared_from_this();  }
    virtual ~CB() {};
    void print() {
        cout << "CB" << endl;
    }
};

class CC : public CA, CB {
public:
    shared_ptr<CC> sharedCCfromThis() { return dynamic_pointer_cast<CC>(sharedCAfromThis());  }
    virtual ~CC() {};
    void print() {
        cout << "CC" << endl;
    }
};

int main()
{
    shared_ptr<CC> cc_ptr = make_shared<CC>();
    cc_ptr->sharedCAfromThis()->print();
    //shared_ptr<C> c_ptr = make_shared<C>();
    //c_ptr->get_shared_b()->printb();
    while (1);
}

but I am wrong the problems are:

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr

Why am I getting this error message?

hi, yes, thank you very much, I change the private to public, but the problem still exists. my gcc version is 8.0; I change the code as below.

class CA  : public enable_shared_from_this<CA> {
public:
    shared_ptr<CA> sharedCAfromThis() { return shared_from_this();  }
    virtual ~CA() {};
    void print() {
        cout << "CA" << endl;
    }
};

class CB : public enable_shared_from_this<CB> {
public:
    shared_ptr<CB> sharedCBfromThis() { return shared_from_this();  }
    virtual ~CB() {};
    void print() {
        cout << "CB" << endl;
    }
};

class CC : public CA, CB, enable_shared_from_this<CC> {
public:
    shared_ptr<CC> sharedCCfromThis() { return dynamic_pointer_cast<CC>(sharedCAfromThis());  }
    virtual ~CC() {};
    void print() {
        cout << "CC" << endl;
    }
};
justin.shen
  • 61
  • 1
  • 5
  • 4
    What is unclear in [reference](https://en.cppreference.com/w/cpp/memory/enable_shared_from_this) *ie. public inheritance is mandatory* ? – rafix07 Aug 31 '19 at 13:27
  • yes public inheritance is mandatory – OznOg Aug 31 '19 at 13:30
  • @rafix07 The unclear part is that is only required since C++17 according to this reference, and question didn't specify standard version. – Yksisarvinen Aug 31 '19 at 13:37
  • 1
    @Yksisarvinen With no language version explicitly specified, I think it's quite reasonable to assume *current latest version* - which, at the moment, is C++17. – Jesper Juhl Aug 31 '19 at 13:49
  • I'm not sure if that smart pointer implementation catches this through some magic, but I'm afraid you're still going to shoot yourself in the foot. Both the `CA` and `CB` subobject have an according `shared_from_this<>` subobject. This may result in two completely independent smart pointers trying to manage the lifetime of the same object, which will lead to desaster. Try to retrieve both smart pointers from an instance, their destruction will then possibly cause double destruction of the instance. – Ulrich Eckhardt Aug 31 '19 at 14:12
  • 1
    May be a dup of: https://stackoverflow.com/questions/16082785/use-of-enable-shared-from-this-with-multiple-inheritance – Eljay Aug 31 '19 at 15:11
  • It's probably a language defect. You should submit to the compiler writers who will submit to the C++ std committee. – curiousguy Aug 31 '19 at 20:08

2 Answers2

5

You should inherit publicly from enable_shared_from_this. Per [util.smartptr.shared.const]/1:

In the constructor definitions below, enables shared_­from_­this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_­shared_­from_­this, then remove_­cv_­t<Y>* shall be implicitly convertible to T* and the constructor evaluates the statement:

if (p != nullptr && p->weak_this.expired())
  p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));

The assignment to the weak_­this member is not atomic and conflicts with any potentially concurrent access to the same object ([intro.multithread]).

If you use private inheritance, the base class is not accessible anymore.

L. F.
  • 19,445
  • 8
  • 48
  • 82
0

It looks like your problem is that you have a duplicate. You need to make sure there is only one enable_shared_from_this.

To do that with classes, you can virtually derive the class:

class A : virtual public enable_shared_from_this<A> ...
class B : virtual public enable_shared_from_this<B> ...

class C : public A, public B ...

Now you have a single instance of the enable_shared_from_this<> and this should work as expected. Otherwise, it may use the version from B which is likely a nullptr, hence the error.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156