2015-08-27 12 views
5

Code tak od jednej z moich książek na przykład:Dlaczego muszę usuwać zasoby podczas korzystania z operatora przypisania kopiowania?

class HasPtr { 
public: 
    HasPtr(const HasPtr& h): ps(new std::string(*h.ps)), i(h.i) { } 
    HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) { } 
    HasPtr& operator=(const HasPtr&); 
    ~HasPtr() { delete ps; } 
private: 
    std::string *ps; 
    int i; 
}; 

HasPtr& HasPtr::operator=(const HasPtr &rhs){ 
    auto newp = new string(*rhs.ps); // copy the underlying string 
    delete ps; // free the old memory 
    ps = newp; // copy data from rhs into this object 
    i = rhs.i; 
    return *this; // return this object 
} 

Wydaje się wewnątrz operatora = może być tylko:

*ps = *rhs.ps 
i = rhs.i 
return *this; 

Bez konieczności najpierw skasować wskaźnik, wydaje się zbędne aby to zrobić. Wspomniał on, że jest napisany w taki sposób, aby pozostawić obiekt w odpowiednim stanie, gdyby wystąpił wyjątek, ale nie ujawniłby go poza tym, ale nie widzę, jaki wyjątek mógłby wystąpić, nawet gdyby moja alternatywa nie poradziła sobie z nim. Dlaczego trzeba najpierw usunąć obiekt przed przypisaniem?

+3

Trzeba przestrzegać zasady trzech [] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) (który jest trywialnie obserwowany przez przestrzeganie [reguły zerowej] (http://stackoverflow.com/q/22806523/315052)). Używaj również funkcji kopiowania i wymiany (http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom), jeśli wdrożysz własny operator przypisania. – jxh

+0

Która książka? –

+1

@LightnessRacesinOrbit C++ Primer Edycja 5th, Rozdział 13.2.1 – AntiElephant

Odpowiedz

4

Wygląda dobrze dla mnie.

I masz rację, std::string cesja already oferuje silną gwarancję wyjątku, więc nadal będziesz pozostawiał obiekt w oryginalnym stanie, jeśli wystąpi wyjątek podczas kopiowania ciągu znaków.

Oczywiście nie ma powodu, aby przydzielać std::string z taką samą liczbą, jak new. można po prostu napisać to zamiast:

class HasNoPtr { 
public: 
    HasNoPtr(const std::string& s): ps(s), i(0) { } 
private: 
    std::string ps; 
    int i; 
}; 
5

W tym przypadku tak, wszystko byłoby dobrze.

Nie przeciekasz dynamicznie przydzielonego ciągu: używasz go ponownie.

Powiązane problemy