7

Ecco un modo molto semplice per definire l'assegnazione mossa per la maggior parte qualsiasi classe con un costruttore mossa:L'assegnazione del movimento tramite destruct + move construct è sicura?

class Foo { 
public: 
    Foo(Foo&& foo);      // you still have to write this one 
    Foo& operator=(Foo&& foo) { 
    if (this != &foo) {    // avoid destructing the only copy 
     this->~Foo();     // call your own destructor 
     new (this) Foo(std::move(foo)); // call move constructor via placement new 
    } 
    return *this; 
    } 
    // ... 
}; 

È questa sequenza di chiamare il proprio distruttore seguito da nuova collocazione sul questo puntatore di sicurezza nello standard C++ 11 ?

+2

Il tuo costruttore di movimento è meglio che sia "noexcept", o tenterai di distruggere un oggetto già distrutto se getta e si allontana in terra UB. – ildjarn

+1

Un buon trucco per spostare/copiare l'assegnazione è semplicemente [prendere il parametro per valore] (http://stackoverflow.com/questions/9746748/does-it-make-sense-to-reuse-destructor-logic-by- utilizzando-stdswap-in-a-move-assegnare/9746772 # 9746772). Un utente si sposterà-costruirà il parametro value o lo copierà (o lo eliderà). Puoi quindi usare 'std :: swap' per scambiare il valore nel tuo oggetto. –

risposta

6

Solo se non si ottiene mai un tipo da questa classe. Se lo fai, questo trasformerà l'oggetto in una mostruosità. È un peccato che lo standard utilizzi questo come esempio per spiegare le vite degli oggetti. È una cosa veramente brutta da fare nel codice del mondo reale.

+0

C'è anche un problema con l'assunzione di memoria allocata di nuovo, manualmente la sua rimozione, quindi il posizionamento di newing? Dovrei standard-approfondire per verificare che questo sia permesso me stesso. – Yakk

+0

@Yakk no, dal momento che non stai [de] assegnando nulla. –

+0

@Yakk no, non ci dovrebbero essere problemi a tale riguardo fintanto che l'oggetto inizialmente assegnato ha dimensioni e requisiti di allineamento sufficienti per l'oggetto che crei tramite il posizionamento nuovo e il puntatore che passi per eliminare è di un tipo appropriato. – bames53

0

Tecnicamente, il codice sorgente è sicuro in questo piccolo esempio. Ma la realtà è che se guardi sempre a Foo, invocherai UB. È così orribilmente pericoloso che non ne vale la pena. Usa lo swap come tutti gli altri - c'è una ragione per questo ed è perché è la scelta giusta. Inoltre, il controllo dell'auto-assegnazione è cattivo.

+2

Copy and swap non è sempre la migliore implementazione. È un modo semplice per ottenere la garanzia di sicurezza eccezionale, ma ci sono dei compromessi. Howard Hinnant ne discute alcuni in parte [questa] (http://stackoverflow.com/a/6687520/365496) risposta. – bames53

+0

La tua preoccupazione riguarda principalmente un autore di classe derivata (erroneamente in questo caso) che chiama l'assegnazione di Foo move, o ci sono più problemi di questo? Questa tecnica richiede che gli autori della sottoclasse superino virtualmente e utilizzino anche la tecnica.La maggior parte dei problemi a cui posso pensare al di là di questo implicano che l'assegnazione del movimento non sia virtuale e quindi la risposta è che l'assegnazione del movimento dovrebbe essere virtuale in quei casi indipendentemente dal fatto che questa tecnica sia utilizzata (siete d'accordo?). Hai preoccupazioni al di là di questo? –