I was using shared_ptr in a project. And at one point I had to store the raw pointers as a void then later convert it back to its shared_ptr form in a callback where the void* was passed. But for some reason the code kept crashing. I didn't understand why since I wasn't getting any compiler errors or warnings. But I noticed that when I was inheriting from std::enable_shared_from_this I wasn't assigning it to be a public inheritance. And that's what was causing the crash.
I wrote an example code and I'm just wondering why it happens.
#include <memory>
#include <iostream>
class TestShared : public std::enable_shared_from_this<TestShared>{
private:
int32_t id;
public:
TestShared(int32_t id){
this->id = id;
}
std::shared_ptr<TestShared> getshared(){
return shared_from_this();
}
int32_t getid(){
return id;
}
};
int main(){
std::shared_ptr<TestShared> ts(new TestShared(0xFF));
void* tsp = ts.get();
std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
std::cout << std::hex << tsn->getid();
return 0;
}
So that code will execute and run fine and I get the expected result.
But when I remove public from the inheritance:
#include <memory>
#include <iostream>
class TestShared : std::enable_shared_from_this<TestShared>{
private:
int32_t id;
public:
TestShared(int32_t id){
this->id = id;
}
std::shared_ptr<TestShared> getshared(){
return shared_from_this();
}
int32_t getid(){
return id;
}
};
int main(){
std::shared_ptr<TestShared> ts(new TestShared(0xFF));
void* tsp = ts.get();
std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
std::cout << std::hex << tsn->getid();
return 0;
}
Then it results in a crash. So why does public make a difference here and why doesn't the compiler give a warning/error?
According to https://en.cppreference.com/w/cpp/memory/enable_shared_from_this
If the inheritance is public, then when
tsis initialized, it "records" in theenable_shared_from_thisbase subobject that it is the owner of theTestSharedobject. Whengetsharedis later called, the base subobject is consulted, and a newshared_ptrobject is created that shares ownership withts.If the inheritance is not public, then when
tsis initialized, it doesn't "know" that there is anenable_shared_from_thissubobject that it needs to write to. Thus, whengetsharedis called, theenable_shared_from_thissubobject doesn't contain any information about who currently owns the object. In C++17, this results in an exception; before C++17, the result is undefined.