Domanda sulla copia superficiale in C ++
-
03-07-2019 - |
Domanda
Supponiamo che io abbia una struttura "quotata" con una variabile membro puntatore int " i " ;. Allocare memoria sull'heap per i nel costruttore predefinito di s. Più avanti in un'altra parte del codice passo un'istanza di s in base al valore ad una funzione. Sto facendo una copia superficiale qui? Supponiamo che non abbia implementato costruttori di copie o operatori di assegnazione o altro per s ... solo il costruttore predefinito.
Soluzione
Per dare seguito a ciò che ha detto @ [don.neufeld.myopenid.com], non è solo una copia superficiale, ma è (scegli la tua scelta) una perdita di memoria o un puntatore penzolante.
// memory leak (note that the pointer is never deleted)
class A
{
B *_b;
public:
A()
: _b(new B)
{
}
};
// dangling ptr (who deletes the instance?)
class A
{
B *_b;
public:
A()
... (same as above)
~A()
{
delete _b;
}
};
Per risolvere il problema, esistono diversi metodi.
Implementa sempre un costruttore di copia e un operatore = nelle classi che utilizzano i puntatori di memoria non elaborata.
class A
{
B *_b;
public:
A()
... (same as above)
~A()
...
A(const A &rhs)
: _b(new B(rhs._b))
{
}
A &operator=(const A &rhs)
{
B *b=new B(rhs._b);
delete _b;
_b=b;
return *this;
};
Inutile dire che questo è un grande dolore e ci sono alcune sottigliezze da ottenere. Non sono nemmeno del tutto sicuro di averlo fatto proprio qui e l'ho fatto un paio di volte. Non dimenticare che devi copiare tutti i membri: se ne aggiungi altri nuovi in ??seguito, non dimenticare di aggiungerli anche tu!
Rendi il costruttore della copia e l'operatore = privati ??nella tua classe. Questa è la "serratura della porta". soluzione. È semplice ed efficace, ma a volte iperprotettivo.
class A : public boost::noncopyable
{
...
};
Non usare mai puntatori non elaborati. Questo è semplice ed efficace. Ci sono molte opzioni qui:
- Utilizza le classi di stringhe anziché i puntatori a caratteri non elaborati
- Usa std :: auto_ptr, boost :: shared_ptr, boost :: scoped_ptr ecc
Esempio:
// uses shared_ptr - note that you don't need a copy constructor or op= -
// shared_ptr uses reference counting so the _b instance is shared and only
// deleted when the last reference is gone - admire the simplicity!
// it is almost exactly the same as the "memory leak" version, but there is no leak
class A
{
boost::shared_ptr<B> _b;
public:
A()
: _b(new B)
{
}
};
Altri suggerimenti
Sì, è una copia superficiale. Ora hai due copie di s (una nel chiamante, una nello stack come parametro), ognuna contenente un puntatore allo stesso blocco di memoria.
Avrai due copie della struttura s
, ognuna delle quali avrà il suo puntatore i
, ma entrambi i puntatori i
avranno lo stesso valore che punta allo stesso indirizzo in memoria - quindi sì, sarà una copia superficiale.