2012-04-03 11 views
6

Ich würde gerne wissen, muss ich Destruktor in Klassen schreiben, wenn ich nicht mehr rohe Zeiger verwenden? Steigere einfach die intelligenten Zeiger.Smart Zeiger & Destruktor

+0

bei http://ideone.com/Kdhj8 demonstriert Vielleicht weiß @simchona etwas, was ich nicht tun, aber intelligente Zeiger haben die Notwendigkeit für die Bereinigung nicht lindern, sie ändern, wie (wenn) es passiert. –

+2

Ich lese diese Frage als, boosten intelligente Zeiger in sich selbst und entfernen Sie die Notwendigkeit zum Schreiben von Destruktoren in fast allen Fällen? Ist das korrekt? – gymbrall

+0

@Yeah, wenn du einen deep_pointer (oder wie auch immer es heißt) hast, brauchst du keine Zuweisung/move/destructor/constructors. (Obwohl Konstruktoren immer noch nützlich sein können) –

Antwort

-2

Sie sollten immer einen Destruktor in Betracht ziehen. Sie würden das verwenden, um alle Ressourcen freizugeben, die Ihre Klasse hält. Oft sind meine smart_ptr Klassendestruktoren leer, aber nicht immer. Dateiströme, Datenbankverbindungen usw. müssen alle ordnungsgemäß bereinigt werden.

+0

All diese Dinge können bereinigt werden, indem man sie in eine RAII-Klasse wie ein 'smart_ptr' einpackt. Mit C++ 11 sollten Klassen-Destruktoren selten sein. –

+1

@Mooing Kein Scherz. Intelligente Zeiger/RAII reduzieren meinen Code um einiges, und meine Destruktoren sind im Allgemeinen leer. Sie brauchen eine Weile, um sich daran zu gewöhnen, aber sie sind es wert, mit Sicherheit zu lernen. – Aura

10

Boost Smart Pointer selbst haben nichts mit der Notwendigkeit eines Destruktors zu tun. Alles, was sie tun, ist, dass Sie auf dem zugewiesenen Speicher, den sie effektiv verwalten, keinen Löschvorgang mehr ausführen müssen. Nachdem Sie das gesagt haben, bevor Sie angefangen haben, intelligente Zeiger zu verwenden, hatten Sie in Ihren Destruktoren Aufrufe zum Löschen und Löschen [], um den Speicher von dynamisch zugewiesenen Klassenmitgliedern zu befreien, und Sie haben nun alle diese regulären Zeiger auf intelligente Zeiger umgestellt wechsle wahrscheinlich einfach zu einem leeren Destruktor, da sie sich jetzt für sich selbst aufräumen, wenn sie außer Reichweite geraten.

Wenn Sie jedoch aus irgendeinem Grund eine Klasse haben, die bereinigt werden muss (Dateibereinigung, Sockets, andere Ressourcen usw.), müssen Sie einen Destruktor bereitstellen, um dies zu tun.

Lassen Sie mich wissen, wenn das hilft.

+0

All diese Dinge können bereinigt werden, indem man sie in eine RAII-Klasse wie ein 'smart_ptr' einpackt. Mit C++ 11 sollten Klassen-Destruktoren selten sein. –

4

Jeder Ressourcentyp sollte eine RAII-Klasse haben, um diese Ressource zu verwalten. Wenn Sie auch einen Smart Pointer mit Deep Copy-Semantik haben (ziemlich einfach zu tun), ist das alles, was Sie brauchen, um Ihre Ressourcen in 99,9% der Fälle zu verwalten. Ich weiß nicht, warum unique_ptr keine tiefen Kopien macht, noch irgendwelche Smart-Pointer, aber wenn Sie diese beiden Dinge haben, müssen Sie keine Kopierkonstruktoren, Bewegungskonstruktoren, Zuweisungsoperatoren, Zuweisungsoperatoren oder Destruktoren schreiben. Sie müssen möglicherweise andere Konstruktoren (einschließlich des Standardkonstruktors) bereitstellen oder nicht, aber das sind fünf weniger Orte, an denen Fehler gemacht werden können.

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

Mit dieser Klasse (oder einer ähnlichen) brauchen Sie nicht viel!

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

Als