2015-03-13 19 views
7

Sto scrivendo una classe che utilizza due oggetti creati utilizzando un'interfaccia C. Gli oggetti assomigliano:unique_ptr, deleter personalizzato e regola zero Zero

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

(in modo simile per bar_t). Perché C++ 11, voglio avvolgerli in un puntatore intelligente in modo da non dover scrivere nessuno dei metodi speciali. La classe avrà la proprietà unica dei due oggetti, in modo da unique_ptr logicamente ha senso ... ma sarebbe ancora dovuto scrivere un costruttore:

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)); 
}; 

Il rovescio della medaglia, con shared_ptr, non avrei dovuto scrivere un costruttore, o usare un alias di tipo, dato che potrei semplicemente passare delete_foo in reset() - anche se ciò renderebbe il mio MyClass copiabili e non lo voglio.

Qual è il modo corretto di scrivere MyClass utilizzando la semantica unique_ptr e continuare a rispettare la regola dello zero?

risposta

8

La classe non ha bisogno di dichiarare un distruttore (otterrà l'implementazione predefinita corretta indipendentemente dal fatto che tu lo dichiari o meno come predefinito), quindi obbedisce ancora alla "Regola dello zero".

Tuttavia, si potrebbe migliorare questo facendo gli oggetti funzione hanno eliminato, piuttosto che puntatori:

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>>; 

Questo ha alcuni vantaggi:

  • il unique_ptr non ha bisogno di memorizzare un extra pointer
  • la funzione di cancellazione può essere richiamata direttamente, piuttosto che tramite un puntatore
  • non è necessario scrivere un costruttore; il costruttore predefinito farà la cosa giusta.
+0

Questo sembra qualcosa che dovrebbe essere nella libreria standard. – rubenvb

+1

Questo è stato fantastico. Ho finito per fare una leggera variazione di questo, con 'template struct unique_ptr_deleter;' che ha una classe privata 'deleter' e quindi' using type = std :: unique_ptr ; '. Salva la quantità di digitazione necessaria ... quindi posso inserirli entrambi insieme ('unique_ptr_deleter_t foo_;') – Barry

Problemi correlati