Sono confuso sullo stato di un oggetto dopo è stato spostato utilizzando semantica di spostamento C++ 0x. La mia comprensione è che una volta che un oggetto è stato spostato, è ancora un oggetto valido, ma il suo stato interno è stato alterato in modo tale che quando viene chiamato il suo distruttore, nessuna risorsa viene deallocata.Oggetti zombi dopo std :: move
Ma se la mia comprensione è corretta, il distruttore di un oggetto spostato dovrebbe essere chiamato.
Ma, che non accade quando effettuo un semplice test:
struct Foo
{
Foo()
{
s = new char[100];
cout << "Constructor called!" << endl;
}
Foo(Foo&& f)
{
s = f.s;
f.s = 0;
}
~Foo()
{
cout << "Destructor called!" << endl;
delete[] s; // okay if s is NULL
}
void dosomething() { cout << "Doing something..." << endl; }
char* s;
};
void work(Foo&& f2)
{
f2.dosomething();
}
int main()
{
Foo f1;
work(std::move(f1));
}
Questa uscita:
Constructor called!
Doing something...
Destructor called!
Avviso il distruttore viene chiamato una sola volta. Questo dimostra che la mia comprensione qui è spenta. Perché il distruttore non è stato chiamato due volte? Ecco la mia interpretazione di ciò che dovrebbe dovuto accadere:
Foo f1
è costruito.Foo f1
è passato awork
, che prende un valore dif2
.- Il costruttore mossa di
Foo
è chiamato, spostando tutte le risorse inf1
af2
. - Ora il distruttore
f2
viene chiamato, che rilascia tutte le risorse. - Ora
f1
s' distruttore viene chiamato, che in realtà non fa nulla dal momento che tutte le risorse sono state trasferite af2
. Tuttavia, il distruttore è chiamato comunque.
Tuttavia, poiché viene chiamato un solo distruttore, il passaggio 4 o il passaggio 5 non si verificano. Ho fatto un backtrace dal distruttore per vedere da dove è stato invocato, e viene richiamato dal passaggio 5. Quindi perché non viene chiamato anche il distruttore f2
?
MODIFICA: OK, ho modificato questo in modo che sia effettivamente in grado di gestire una risorsa. (Un buffer di memoria interno.) Tuttavia, ottengo lo stesso comportamento in cui il distruttore viene chiamato solo una volta.
su quale compilatore stai testando? – jalf
gcc 4.3 ......................... – Channel72
In tal caso, vale la pena notare che è scritto contro una versione molto più vecchia del C++ 0x bozza. E spostare la semantica è stata modificata un bel po 'da allora. Ad esempio, credo che un compilatore più recente avrebbe rifiutato del tutto il codice prima di aver aggiunto 'std :: move'. Non sarebbe in grado di chiamare 'work' perché l'argomento era effettivamente un riferimento lvalue perché era chiamato. – jalf