c++ c++11 move-semantics unique-ptr

c++ - ¿Cómo uso un eliminador personalizado con un miembro std:: unique_ptr?



c++11 move-semantics (4)

Asumiendo que create y destroy son funciones gratuitas (lo que parece ser el caso del fragmento de código del PO) con las siguientes firmas:

Bar* create(); void destroy(Bar*);

Puedes escribir tu clase Foo así

class Foo { std::unique_ptr<Bar, void(*)(Bar*)> ptr_; // ... public: Foo() : ptr_(create(), destroy) { /* ... */ } // ... };

Tenga en cuenta que no necesita escribir ningún lambda o eliminador personalizado aquí porque destroy ya es un eliminador.

Tengo una clase con un miembro unique_ptr.

class Foo { private: std::unique_ptr<Bar> bar; ... };

La barra es una clase de terceros que tiene una función create () y una función destroy ().

Si quisiera usar un std::unique_ptr con él en una función independiente, podría hacerlo:

void foo() { std::unique_ptr<Bar, void(*)(Bar*)> bar(create(), [](Bar* b){ destroy(b); }); ... }

¿Hay alguna manera de hacer esto con std::unique_ptr como miembro de una clase?


Es posible hacer esto limpiamente usando un lambda en C ++ 11 (probado en G ++ 4.8.2).

Dado este typedef reutilizable:

template<typename T> using deleted_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>;

Puedes escribir:

deleted_unique_ptr<Foo> foo(new Foo(), [](Foo* f) { customdeleter(f); });

Por ejemplo, con un FILE* :

deleted_unique_ptr<FILE> file( fopen("file.txt", "r"), [](FILE* f) { fclose(f); });

Con esto obtienes los beneficios de la limpieza segura de excepciones usando RAII, sin necesidad de probar / atrapar ruido.


Simplemente puede usar std::bind con una función de destrucción.

std::unique_ptr<Bar, std::function<void(Bar*)>> bar(create(), std::bind(&destroy, std::placeholders::_1));

Pero por supuesto también puedes usar una lambda.

std::unique_ptr<Bar, std::function<void(Bar*)>> ptr(create(), [](Bar* b){ destroy(b);});


Solo necesitas crear una clase de eliminador:

struct BarDeleter { void operator()(Bar* b) { destroy(b); } };

y proporcionarlo como el argumento de la plantilla de unique_ptr . Aún tendrá que inicializar unique_ptr en sus constructores:

class Foo { public: Foo() : bar(create()), ... { ... } private: std::unique_ptr<Bar, BarDeleter> bar; ... };

Hasta donde yo sé, todas las bibliotecas c ++ populares implementan esto correctamente; ya que BarDeleter realidad no tiene ningún estado, no necesita ocupar ningún espacio en el unique_ptr .