Obtendo um unique_ptr para uma classe que herda enable_shared_from_this
Normalmente eu prefiro voltarunique_ptr
de Fábricas. Recentemente, cheguei ao problema de retornar umunique_ptr
para uma classe que herdaenable_shared_from_this
. Os usuários desta classe podem acidentalmente causar uma chamada parashared_from_this()
, embora não seja de propriedade de nenhumshared_ptr
, o que resulta com umstd::bad_weak_ptr
exceção (ou comportamento indefinido até C ++ 17, que geralmente é implementado como uma exceção).
Uma versão simples do código:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
shared_ptr<Foo> get_shared() {return shared_from_this();}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = pb2->get_shared();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
pb5->doIt();
}
Uma solução possível é alterar o método de fábrica para retornarshared_ptr
mas não é isso que estou procurando, pois em muitos casos não há realmente necessidade de compartilhamento e isso tornará as coisas menos eficientes.
A questão é como conseguir o seguinte:
permitir que a fábrica retorneunique_ptr
permitirunique_ptr
desta classe para se tornar compartilhadopermitirshared_ptr
dessa classe para obter cópias compartilhadas (viashared_from_this()
)evitar falhas quandounique_ptr
dessa classe tenta ser compartilhado com isso (chamandoget_shared
no exemplo acima)Os itens 1 a 3 são preenchidos com o código acima,o problema está no item 4.