2015-03-13 11 views
7

Ich schreibe eine Klasse, die zwei Objekte verwendet, die mit einer C-Schnittstelle erstellt wurden. Die Objekte wie folgt aussehen:unique_ptr, benutzerdefinierter Deleter und Rule of Zero

typedef struct... foo_t; 
foo_t* create_foo(int, double, whatever); 
void delete_foo(foo_t*); 

(ähnlich für bar_t). Weil ich C++ 11 habe, möchte ich diese in einen intelligenten Zeiger schreiben, so dass ich keine der speziellen Methoden schreiben muss. Die Klasse hat einzigartiges Eigentum an den beiden Objekte, so unique_ptr logisch sinnvoll ... aber ich würde noch einen Konstruktor schreiben muß:

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

struct MyClass { 
    unique_ptr_deleter<foo_t> foo_; 
    unique_ptr_deleter<bar_t> bar_; 

    MyClass() 
     : foo_{nullptr, delete_foo} 
     , bar_{nullptr, delete_bar} 
    { } 

    ~MyClass() = default; 

    void create(int x, double y, whatever z) { 
     foo_.reset(create_foo(x, y, z)); 
     bar_.reset(create_bar(x, y, z)); 
}; 

Auf der anderen Seite, mit shared_ptr, würde ich nicht haben schreibe einen Konstruktor, oder benutze einen Typalias, da ich einfach delete_foo in reset() übergeben könnte - obwohl das meine MyClass kopierbar machen würde und ich das nicht will.

Was ist der richtige Weg, um MyClass mit unique_ptr Semantik zu schreiben und immer noch an Rule of Zero zu halten?

Antwort

8

Ihre Klasse muss keinen Destruktor deklarieren (es wird die korrekte Standardimplementierung erhalten, unabhängig davon, ob Sie sie als Standard deklarieren), also gehorcht sie immer noch der "Rule of Zero".

Allerdings könnten Sie diese verbessern, indem die Löscher Funktionsobjekte zu machen, anstatt Zeiger:

template <typename T> struct deleter; 
template <> struct deleter<foo_t> { 
    void operator()(foo_t * foo){delete_foo(foo);} 
}; 
template <> struct deleter<bar_t> { 
    void operator()(bar_t * bar){delete_bar(bar);} 
}; 

template <typename T> 
using unique_ptr_deleter = std::unique_ptr<T, deleter<T>>; 

Dies hat einige Vorteile:

  • die unique_ptr braucht nicht extra zu speichern Zeiger
  • Die Löschfunktion kann direkt aufgerufen werden, anstatt über einen Zeiger
  • Sie müssen keinen Konstruktor schreiben; Der Standardkonstruktor wird das Richtige tun.
+0

Dies sieht aus wie etwas, das in der Standardbibliothek sein sollte. – rubenvb

+1

Das war großartig. Ich habe eine leichte Variante davon gemacht, mit 'template struct unique_ptr_deleter;' mit einer privaten Klasse 'deleter' und dann' using type = std :: unique_ptr ; '. Speichert die Menge der notwendigen Eingabe ... dann kann ich beides zusammenhalten ('unique_ptr_deleter_t foo_;') – Barry

Verwandte Themen