usar teclado izquierdo hacer dar con como clic activar c++ smart-pointers unique-ptr ownership-semantics

c++ - teclado - ¿Mala práctica para devolver unique_ptr para el puntero sin formato como semántica de propiedad?



usar teclado como mouse windows 10 (3)

He escrito un método de fábrica estático que devuelve un nuevo objeto Foobar poblado de otro objeto de datos. Recientemente he estado obsesionado con la semántica de propiedad y me pregunto si estoy transmitiendo el mensaje correcto al hacer que este método de fábrica devuelva un unique_ptr .

class Foobar { public: static unique_ptr<Foobar> factory(DataObject data); }

Mi intención es decirle al código del cliente que poseen el puntero. Sin un puntero inteligente, simplemente devolvería Foobar* . Sin embargo, me gustaría hacer que se elimine esta memoria para evitar posibles errores, por lo que unique_ptr pareció una solución adecuada. Si el cliente desea extender la vida útil del puntero, simplemente llama a .release() una vez que obtiene el unique_ptr .

Foobar* myFoo = Foobar::factory(data).release();

Mi pregunta viene en dos partes:

  1. ¿Este enfoque transmite la semántica de propiedad correcta?
  2. ¿Es esto una "mala práctica" devolver unique_ptr lugar de un puntero sin unique_ptr ?

Devolver un std::unique_ptr de un método de fábrica está bien y debería ser una práctica recomendada. El mensaje que transmite es (IMO): ahora eres el único propietario de este objeto. Además, para su conveniencia, el objeto sabe cómo destruirse a sí mismo.

Creo que esto es mucho mejor que devolver un puntero sin formato (donde el cliente tiene que recordar cómo y si deshacerse de este puntero).

Sin embargo, no entiendo su comentario sobre la liberación del puntero para extender su vida útil. En general, casi no veo ningún motivo para solicitar la release de un smartpointer, ya que creo que los punteros siempre deberían gestionarse mediante algún tipo de estructura RAII (casi la única situación en la que llamo release es poner el puntero en una estructura de gestión diferente, por ejemplo un unique_ptr con un eliminador diferente, después de que hice algo para garantizar una limpieza adicional).

Por lo tanto, el cliente puede (y debe) simplemente almacenar el unique_ptr algún lugar (como otro unique_ptr , que ha sido creado a partir del objeto devuelto) mientras necesiten el objeto (o un shared_ptr , si necesitan varias copias del puntero) . Entonces, el código del cliente debería verse más como esto:

std::unique_ptr<FooBar> myFoo = Foobar::factory(data); //or: std::shared_ptr<FooBar> myFoo = Foobar::factory(data);

Personalmente, también agregaría un typedef para el tipo de puntero devuelto (en este caso std::unique_ptr<Foobar> ) y / o el eliminador usado (en este caso std :: default_deleter) para su objeto de fábrica. Eso lo hace más fácil si luego decide cambiar la asignación de su puntero (y por lo tanto necesita un método diferente para la destrucción del puntero, que será visible como un segundo parámetro de plantilla de std::unique_ptr ). Entonces haría algo como esto:

class Foobar { public: typedef std::default_deleter<Foobar> deleter; typedef std::unique_ptr<Foobar, deleter> unique_ptr; static unique_ptr factory(DataObject data); } Foobar::unique_ptr myFoo = Foobar::factory(data); //or: std::shared_ptr<Foobar> myFoo = Foobar::factory(data);


Transmite exactamente la semántica correcta y es la forma en que creo que todas las fábricas en C ++ deberían funcionar: std::unique_ptr<T> no impone ningún tipo de semántica de propiedad y es extremadamente barato.


Un std::unique_ptr posee de forma exclusiva el objeto al que apunta. Dice "Poseo este objeto, y nadie más lo hace".

Eso es exactamente lo que estás tratando de expresar: estás diciendo "llamador de esta función: ahora eres el único propietario de este objeto, hazlo como quieras, su vida es tu responsabilidad".