2015-08-27 6 views
5

codice come questo da uno dei miei libri, per esempio:Perché è necessario eliminare le risorse quando si utilizza l'operatore di assegnazione copia?

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 
} 

Sembra l'interno dell'operatore = potrebbe essere solo:

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

senza la necessità di eliminare il puntatore prima, sembra ridondante fare così. Ha menzionato che è stato scritto in modo da lasciare l'oggetto in uno stato adatto nel caso in cui si verificasse un'eccezione, ma non lo ha divulgato oltre, ma non vedo quale eccezione potrebbe verificarsi che nemmeno la mia alternativa potrebbe gestire. Perché è necessario eliminare prima l'oggetto prima di assegnarlo?

+3

è necessario osservare il [regola del tre] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) (che viene banalmente osservato seguendo la [regola zero] (http://stackoverflow.com/q/22806523/315052)). Utilizza anche [copy-and-swap] (http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) se implementi il ​​tuo operatore di assegnazione. – jxh

+0

Quale libro? –

+1

@LightnessRacesinOrbit C++ Primer 5th Edition, Capitolo 13.2.1 – AntiElephant

risposta

4

Questo mi sembra buono.

E hai ragione, l'assegnazione std::stringalready offre una forte garanzia di eccezione in modo da lasciare l'oggetto nel suo stato originale nel caso in cui si verificasse un'eccezione copiando la stringa.

Ovviamente non c'è motivo di allocare uno std::string con new così. Si potrebbe semplicemente scrivere questo invece:

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

In questo caso, sì, andrebbe bene.

Non stai perdendo la stringa allocata dinamicamente: la stai riutilizzando.