2012-10-29 13 views
16

Sono confuso su quando un costruttore di mosse viene chiamato contro un costruttore di copie. che ho letto le seguenti fonti:Quando viene richiamato Move Constructor?

Move constructor is not getting called in C++0x

Move semantics and rvalue references in C++11

msdn

Tutte queste fonti sono o troppo complicata (Voglio solo un semplice esempio) o solo mostrano come scrivere move constructor, ma non come chiamarlo. Ive ha scritto un problema semplice per essere più precisi:

const class noConstruct{}NoConstruct; 
class a 
{ 
private: 
    int *Array; 
public: 
    a(); 
    a(noConstruct); 
    a(const a&); 
    a& operator=(const a&); 
    a(a&&); 
    a& operator=(a&&); 
    ~a(); 
}; 

a::a() 
{ 
    Array=new int[5]{1,2,3,4,5}; 
} 
a::a(noConstruct Parameter) 
{ 
    Array=nullptr; 
} 
a::a(const a& Old): Array(Old.Array) 
{ 

} 
a& a::operator=(const a&Old) 
{ 
    delete[] Array; 
    Array=new int[5]; 
    for (int i=0;i!=5;i++) 
    { 
     Array[i]=Old.Array[i]; 
    } 
    return *this; 
} 
a::a(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
} 
a& a::operator=(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
    return *this; 
} 
a::~a() 
{ 
    delete[] Array; 
} 

int main() 
{ 
    a A(NoConstruct),B(NoConstruct),C; 
    A=C; 
    B=C; 
} 

attualmente A, B, e C tutti hanno differenti valori di puntatore. Vorrei che A avesse un nuovo puntatore, B che avesse il vecchio puntatore di C e C che avesse un puntatore nullo.

un po 'fuori tema, ma se si potesse suggerire una documentazione in cui potrei conoscere in dettaglio queste nuove funzionalità sarei grato e probabilmente non avrei bisogno di fare molte altre domande.

+0

su una questione in parte correlata, si potrebbe voler controllare la copia e scambiare idioma http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom per la vostra assegnazione operatore. – undu

+0

[domande frequenti correlate] (http: // stackoverflow.it/questions/3106110 /) – fredoverflow

risposta

22

Un costruttore mossa è chiamata:

  • quando un inizializzatore oggetto è std::move(something)
  • quando un inizializzatore oggetto è std::forward<T>(something) e T non è un tipo di riferimento lvalue (utile nella programmazione modello per "perfetta inoltro ")
  • quando un inizializzatore di oggetti è temporaneo e il compilatore non elimina completamente la copia/sposta
  • quando restituisce un oggetto classe funzione locale per valore e il compilatore non eliminare la copia/spostare completamente
  • quando lancio un oggetto classe funzione-locale e il compilatore non eliminare la copia/spostare completamente

Questo non è un elenco completo. Si noti che un "inizializzatore di oggetti" può essere un argomento di funzione, se il parametro ha un tipo di classe (non di riferimento).

a RetByValue() { 
    a obj; 
    return obj; // Might call move ctor, or no ctor. 
} 

void TakeByValue(a); 

int main() { 
    a a1; 
    a a2 = a1; // copy ctor 
    a a3 = std::move(a1); // move ctor 

    TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. 

    a a4 = RetByValue(); // Might call move ctor, or no ctor. 

    a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) 
} 
4

Prima di tutto, il costruttore della copia è danneggiato. Sia il copiato da sia copiato in oggetti punterà allo stesso Array e tenteranno entrambi a delete[] quando escono dal campo di applicazione, determinando un comportamento non definito. Per risolverlo, crea una copia dell'array.

a::a(const a& Old): Array(new int[5]) 
{ 
    for(size_t i = 0; i < 5; ++i) { 
    Array[i] = Old.Array[i]; 
    } 
} 

Ora, l'assegnazione mossa non viene eseguita come si vuole che sia, perché entrambe le istruzioni di assegnazione assegnano da lvalue, invece di utilizzare rvalues. Per le mosse da eseguire, è necessario spostarsi da un valore rval o deve essere un contesto in cui un lvalue può essere considerato un valore rvalore (ad esempio l'istruzione return di una funzione).

Per ottenere l'effetto desiderato utilizzare std::move per creare un riferimento di rvalue.

A=C;    // A will now contain a copy of C 
B=std::move(C); // Calls the move assignment operator 
+0

'B = std :: move (C); // Chiama l'operatore di assegnazione delle copie "Non dovrebbe essere l'operatore di assegnazione delle mosse? Successivamente, C potrebbe non essere più quello a cui era abituato. – RainingChain

+0

@RainingChain Sì, quello era un errore di battitura, grazie! – Praetorian

Problemi correlati