2015-01-27 15 views
5

Ho giocato con std :: vector per capire quando gli oggetti sono costruiti, destrutturati, copiati e costruiti. Per fare così, ho scritto il seguente programmaRidimensiona su std :: vector non chiama move constructor

#include <iostream> 
#include <vector> 

class Test { 
public: 
    Test() { 
     std::cout << "Constructor called for " << this << std::endl; 
    } 
    Test(const Test& x) { 
     std::cout << "Copy Constructor called for " << this << std::endl; 
    } 
    Test(Test&& x) { 
     std::cout << "Move Constructor called for " << this << std::endl; 
    } 
    ~Test() { 
     std::cout << "Destructor called for " << this << std::endl; 
    } 
}; 

int main() { 
    std::vector<Test> a(1); 
    a.resize(3); 

    return 0; 
} 

Quando una viene ridimensionata, riallocazione accade. La mia ipotesi sarebbe che l'oggetto a [0] è stato spostato nel nuovo a [0]. Ma con libC++ e libstdC++ sembra che sia chiamato il costruttore di copie e non il costruttore di move. C'è qualche ragione per un tale comportamento?

risposta

9

Ho appena trovato la risposta alla domanda. Il costruttore di mosse deve essere dichiarato nient'altro per farlo. Quando è stata apportata una tale modifica

Test(Test&& x) noexcept { 
    std::cout << "Move Constructor called for " << this << std::endl; 
} 

viene chiamato il costruttore di movimento.

+0

si potrebbe pensare che l'ottimizzatore dovrebbe dedurre che il vostro costruttore non buttare e usarlo anche senza l'identificatore noexcept. – gbjbaanb

+0

@gbjbaanb Il compilatore _ever_ dedifica i modificatori? Non per 'const' (come postfix). – ApproachingDarknessFish

+3

@gbjbaanb Penso che tecnicamente potresti fare il lancio di 'cout' tramite [' ios :: exceptions'] (http://en.cppreference.com/w/cpp/io/basic_ios/exceptions). –

2

Proprio come ha risposto la risposta di @ InsideLoop, il costruttore di spostamenti deve essere dichiarato "noexcept" da chiamare.

è perché nel vettore :: ridimensionare() stack di chiamata di funzione, possiamo trovare move_if_noexcept() è chiamato nella funzione __construct_backward(). (Vedi [percorso di libreria]/include/C++/v1/linea di memoria: 1531)

construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1)); 

Secondo lo standard C++ 11, sappiamo che il costruttore mossa viene utilizzato per il valore diritto temporaneo in condizioni normali. Quindi l'eccezione di lancio del costruttore di mosse è una cosa così pericolosa, e possiamo dichiarare "noexcept" per il costruttore di mosse per evitarlo.

Utilizzo di move_if_noexcept(), sebbene la perdita di prestazioni, ma può rendere il processo sicuro. E la funzione attiverà il costruttore di mosse quando il costruttore di mosse viene dichiarato "noexcept".

(Ci scusiamo per il mio povero inglese.)