Obtener un unique_ptr para una clase que hereda enable_shared_from_this
Normalmente prefiero regresarunique_ptr
de las fábricas. Recientemente llegué al problema de devolver ununique_ptr
para una clase que heredaenable_shared_from_this
. Los usuarios de esta clase pueden provocar accidentalmente una llamada ashared_from_this()
, aunque no es propiedad de ningúnshared_ptr
, que resulta con unstd::bad_weak_ptr
excepción (o comportamiento indefinido hasta C ++ 17, que generalmente se implementa como una excepción).
Una versión simple del 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();
}
Una posible solución es cambiar el método de fábrica para devolvershared_ptr
pero esto no es lo que estoy buscando, ya que en muchos casos no hay necesidad de compartir y esto hará que las cosas sean menos eficientes.
La pregunta es cómo lograr todo lo siguiente:
permitir que la fábrica regreseunique_ptr
permitirunique_ptr
de esta clase para ser compartidapermitirshared_ptr
de esta clase para obtener copias compartidas (a través deshared_from_this()
)evitar el fracaso cuandounique_ptr
de esta clase intenta ser compartida a partir de esto (llamandoget_shared
en el ejemplo anterior)Los artículos 1 a 3 se cumplen con el código anterior,el problema es con el ítem 4.