Guideline
Mai eliminare i membri mossa speciale.
Nel codice tipico (come nella domanda), vi sono due motivi per eliminare i membri di spostamento. Una di queste motivazioni produce codice errato (come nel tuo esempio), e per l'altra motivazione la cancellazione dei membri del movimento è ridondante (non fa male né bene).
Se si dispone di una classe copiabile e non si desidera spostare membri, semplicemente non li dichiarano (che non comprende l'eliminazione di loro). I membri eliminati sono ancora dichiarati. I membri eliminati partecipano alla risoluzione di sovraccarico. I membri non presenti non lo fanno. Quando si crea una classe con un costruttore di copie valido e un membro di spostamento eliminato, non è possibile restituirlo per valore da una funzione poiché la risoluzione di sovraccarico si associa al membro di spostamento eliminato.
A volte le persone vogliono dire: questa classe non è né mobile né copiabile. È corretto cancellare sia la copia che i membri del movimento. Tuttavia è sufficiente eliminare i membri della copia (purché i membri del movimento non siano dichiarati). I membri della copia dichiarati (anche cancellati) inibiscono il dal compilatore di dichiarare i membri del movimento. Quindi in questo caso i membri delle mosse eliminate sono semplicemente ridondanti.
Se si dichiarano membri mossa cancellati, anche se vi capita di prendere il caso in cui esso è ridondante e non corretto, ogni volta che qualcuno legge il codice, hanno bisogno di riscoprire se il tuo caso è ridondante o non corretti . Rendi più facile l'accesso ai lettori del tuo codice e non eliminare mai i membri del movimento.
Il caso non corretto:
struct CopyableButNotMovble
{
// ...
CopyableButNotMovble(const CopyableButNotMovble&);
CopyableButNotMovble& operator=(const CopyableButNotMovble&);
CopyableButNotMovble(CopyableButNotMovble&&) = delete;
CopyableButNotMovble& operator=(CopyableButNotMovble&&) = delete;
// ...
};
Ecco esempio di codice che probabilmente aspetta di lavorare con CopyableButNotMovble
ma avrà esito negativo in fase di compilazione:
CopyableButNotMovble
get()
{
CopyableButNotMovble x;
return x;
}
int
main()
{
CopyableButNotMovble x = get();
}
test.cpp:22:26: error: call to deleted constructor of 'CopyableButNotMovble'
CopyableButNotMovble x = get();
^ ~~~~~
test.cpp:7:5: note: 'CopyableButNotMovble' has been explicitly marked deleted here
CopyableButNotMovble(CopyableButNotMovble&&) = delete;
^
1 error generated.
Il modo corretto per farlo è:
struct CopyableButNotMovble
{
// ...
CopyableButNotMovble(const CopyableButNotMovble&);
CopyableButNotMovble& operator=(const CopyableButNotMovble&);
// ...
};
Il caso ridondante:
struct NeitherCopyableNorMovble
{
// ...
NeitherCopyableNorMovble(const NeitherCopyableNorMovble&) = delete;
NeitherCopyableNorMovble& operator=(const NeitherCopyableNorMovble&) = delete;
NeitherCopyableNorMovble(NeitherCopyableNorMovble&&) = delete;
NeitherCopyableNorMovble& operator=(NeitherCopyableNorMovble&&) = delete;
// ...
};
Il modo più leggibile per farlo è:
struct NeitherCopyableNorMovble
{
// ...
NeitherCopyableNorMovble(const NeitherCopyableNorMovble&) = delete;
NeitherCopyableNorMovble& operator=(const NeitherCopyableNorMovble&) = delete;
// ...
};
Aiuta se si effettua una pratica di raggruppare sempre tutti e 6 i membri del speciali vicino alla parte superiore del vostro dichiarazione di classe, nello stesso ordine, saltando quelli che non vuoi dichiarare. Questa pratica rende più facile per i lettori del tuo codice determinare rapidamente che non hai intenzionalmente dichiarato alcun particolare membro speciale.
Per esempio, ecco il modello che segue:
class X
{
// data members:
public:
// special members
~X();
X();
X(const X&);
X& operator=(const X&);
X(X&&);
X& operator=(X&&);
// Constructors
// ...
};
No. Se si vuole che tutto sia una copia, allora non dichiarare le componenti di movimento; non definirli come cancellati. http://stackoverflow.com/questions/26489837/why-do-deleted-move-semantics-cause-problems-with-stdvector –
Hai esattamente ragione su 'operator *'! Yikes! Corretto. – blazs
'std :: shared_ptr' ha operazioni di spostamento personalizzate perché il meccanismo di conteggio dei riferimenti sottostante è sicuro dalla concorrenza. Le operazioni di spostamento personalizzate possono quindi evitare l'incremento atomico. – dyp