Mi piacerebbe sapere che devo scrivere distruttore nelle classi quando non uso più i puntatori grezzi? Basta aumentare i puntatori intelligenti.Puntatori intelligenti e distruttore
risposta
Si dovrebbe sempre considerare di fornire un distruttore. Lo useresti per liberare tutte le risorse della tua classe. Spesso i miei distruttori di classe smart_ptr sono vuoti ma non sempre. I flussi di file, le connessioni al database, ecc. Hanno tutti bisogno di una corretta pulizia.
Tutte queste cose possono essere ripulite avvolgendole in una classe RAII, come una 'smart_ptr'. Con C++ 11, i distruttori di classe dovrebbero essere rari. –
@Mooing No scherzo. I puntatori intelligenti/RAII riducono il mio codice di molto ei miei distruttori sono generalmente vuoti. Ci vuole un po 'per abituarsi, ma valgono sicuramente la pena di imparare. – Aura
Aumentare i puntatori intelligenti da soli non hanno nulla a che fare con la necessità di un distruttore. Tutto ciò che fanno è rimuovere la necessità di chiamare la cancellazione sulla memoria allocata che stanno effettivamente gestendo. Quindi, detto questo, se prima di iniziare a usare puntatori intelligenti tutto ciò che avevi nei tuoi distruttori erano chiamate per eliminare ed eliminare [] liberando la memoria dei membri della classe allocati dinamicamente e ora hai passato tutti quei puntatori regolari a puntatori intelligenti, potresti probabilmente basta passare a un distruttore vuoto poiché ora si ripuliscono da soli quando escono dal campo di applicazione.
Tuttavia, se per qualsiasi motivo, si dispone di una classe che deve eseguire la pulizia (pulizia dei file, socket, altre risorse, ecc.) Sarà comunque necessario fornire un distruttore per farlo.
Fammi sapere se questo aiuta.
Tutte queste cose possono essere ripulite avvolgendole in una classe RAII, come una 'smart_ptr'. Con C++ 11, i distruttori di classe dovrebbero essere rari. –
Ogni tipo di risorsa deve avere una classe RAII per gestire tale risorsa. Se hai anche un puntatore intelligente con semantica di copia profonda (abbastanza facile da fare), questo è tutto ciò che serve per gestire le tue risorse il 99,9% delle volte. Non so perché unique_ptr
non faccia copie profonde, né alcun puntatore intelligente di boost, ma se hai queste due cose, non hai bisogno di scrivere costruttori di copie, spostare costruttori, operatori di assegnazione, spostare gli operatori di assegnazione, né distruttori. Potresti o meno dover fornire altri costruttori (incluso il costruttore predefinito), ma questo è cinque posti in meno per fare errori.
#include <memory>
template<class Type, class Del = std::default_delete<Type> >
class deep_ptr : public std::unique_ptr<Type, Del> {
public:
typedef std::unique_ptr<Type, Del> base;
typedef typename base::element_type element_type;
typedef typename base::deleter_type deleter_type;
typedef typename base::pointer pointer;
deep_ptr() : base() {}
//deep_ptr(std::nullptr_t p) : base(p) {} //GCC no has nullptr_t?
explicit deep_ptr(pointer p) : base() {}
deep_ptr(pointer p, const typename std::remove_reference<Del>::type &d) : base(p, d) {} //I faked this, it isn't quite right
deep_ptr(pointer p, typename std::remove_reference<Del>::type&& d): base(p, d) {}
deep_ptr(const deep_ptr& rhs) : base(new Type(*rhs)) {}
template<class Type2, class Del2>
deep_ptr(const deep_ptr<Type2, Del2>& rhs) : base(new Type(*rhs)) {}
deep_ptr(deep_ptr&& rhs) : base(std::move(rhs)) {}
template<class Type2, class Del2>
deep_ptr(deep_ptr<Type2, Del2>&& rhs) : base(std::move(rhs)) {}
deep_ptr& operator=(const deep_ptr& rhs) {base::reset(new Type(*rhs)); return *this;}
template<class Type2, class Del2>
deep_ptr& operator=(const deep_ptr<Type2, Del2>& rhs) {base::reset(new Type(*rhs)); return *this;}
deep_ptr& operator=(deep_ptr&& rhs) {base::reset(rhs.release()); return *this;}
template<class Type2, class Del2>
deep_ptr& operator=(deep_ptr<Type2, Del2>&& rhs) {base::reset(rhs.release()); return *this;}
void swap(deep_ptr& rhs) {base::swap(rhs.ptr);}
friend void swap(deep_ptr& lhs, deep_ptr& rhs) {lhs.swap(rhs.ptr);}
};
Con questa classe (o una simile), non è necessario molto!
struct dog {
deep_ptr<std::string> name;
};
int main() {
dog first; //default construct a dog
first.name.reset(new std::string("Fred"));
dog second(first); //copy construct a dog
std::cout << *first.name << ' ' << *second.name << '\n';
second.name->at(3) = 'o';
std::cout << *first.name << ' ' << *second.name << '\n';
second = first; //assign a dog
std::cout << *first.name << ' ' << *second.name << '\n';
}
Come dimostrato in http://ideone.com/Kdhj8
Forse @simchona sa qualcosa che io non faccio, ma puntatori intelligenti non alleviare il bisogno di pulizia, hanno solo cambiare il modo (quando) accade. –
Sto leggendo questa domanda come, fare aumentare i puntatori intelligenti di per sé rimuovere la necessità di scrivere i distruttori in quasi tutti i casi? È corretto? – gymbrall
@ Sì, se si ha un deep_pointer (o come si chiama), non è necessario assegnare/spostare/distruttore/costruttori. (Sebbene i costruttori possano ancora essere a volte utili) –