2016-02-04 18 views
5

In C++ 11, è possibile impostare in modo esplicito una funzione membro speciale, se la sua generazione implicita è stata automaticamente impedita.Attivazione della generazione della funzione membro speciale predefinita predefinita

Tuttavia, l'impostazione predefinita predefinita di una funzione membro speciale annulla l'eliminazione implicita causata dalla dichiarazione manuale di alcune delle altre funzioni membro speciali (operazioni di copia, distruttore, ecc.), Non impone al compilatore di generare la funzione e il codice è considerato ben formato anche se la funzione non può in effetti essere generata.

Si consideri il seguente scenario:

struct A 
{ 
    A()   = default; 
    A (const A&) = default; 
    A (A&&)  = delete; // Move constructor is deleted here 
}; 

struct B 
{ 
    B()   = default; 
    B (const B&) = default; 
    B (B&&)  = default; // Move constructor is defaulted here 

    A a; 
}; 

Il costruttore mossa in B non verrà generato dal compilatore, perché così facendo avrebbe causato un errore di compilazione (costruttore mossa di A viene eliminato). Senza cancellare esplicitamente il costruttore di A, il costruttore di movimento di B verrebbe generato come previsto (copia A, anziché spostarlo).

di tentare di spostare un oggetto del genere silenziosamente utilizzare il costruttore copia anziché:

B b; 
B b2 (std::move(b)); // Will call B's copy constructor 

C'è un modo per forzare il compilatore nella generazione sia la funzione o emettere un errore di compilazione, se non si può? Senza questa garanzia, è difficile fare affidamento sui costruttori di movimento predefiniti, se un singolo costruttore eliminato può disabilitare lo spostamento per le gerarchie di un intero oggetto.

+0

Non dovresti sapere se i membri che stai includendo sono mobili o no? – NathanOliver

+2

Possono essere mobili quando la classe è stata originariamente implementata, tuttavia, se più membri vengono aggiunti in seguito, il requisito mobile potrebbe essere trascurato (specialmente se sono aggiunti da qualcun altro). –

+1

Va notato che un tipo che cancella il suo costruttore di mosse ma * non * il suo costruttore di copia è molto ... bizzarro. Non c'è assolutamente nulla da guadagnare facendo questo. Quindi potrebbe essere meglio ignorare questo caso, considerandolo come il risultato di qualcuno che fa qualcosa di idiota senza motivo. –

risposta

3

C'è un modo per rilevare tipi come A. Ma solo se il tipo esplicitamente elimina il costruttore di movimento. Se il costruttore di movimento viene generato implicitamente come eliminato, quindi non parteciperà alla risoluzione di sovraccarico. Questo è il motivo per cui B è mobile anche se non lo è lo A. Bdefault s il costruttore di movimento, il che significa che viene eliminato in modo implicito, quindi avviene la copia.

B è quindi spostabile costruibile. Tuttavia, A non lo è. Quindi si tratta di una semplice questione di questo:

struct B 
{ 
    static_assert(is_move_constructible<A>::value, "Oops..."); 

    B()   = default; 
    B (const B&) = default; 
    B (B&&)  = default; // Move constructor is defaulted here 

    A a; 
}; 

Ora, non v'è alcuna generale modo per causare alcun tipo che contiene di sola copia tipi di fare quello che vuoi. Cioè, devi dichiarare staticamente ogni tipo singolarmente; non è possibile inserire alcune sintassi nel costruttore di spostamento predefinito per fare fallire i tentativi di spostamento B.

Il motivo deve essere in parte dovuto alla compatibilità con le versioni precedenti. Pensa a tutto il codice pre-C++ 11 che ha dichiarato i costruttori di copia definiti dall'utente. Con le regole della generazione del costruttore di spostamenti in C++ 11, tutti loro avrebbero eliminato i costruttori di movimento. Il che significa che qualsiasi codice del modulo T t = FuncReturningTByValue(); non funzionerebbe, anche se ha funzionato bene in C++ 98/03 chiamando il costruttore di copie. Quindi il problema del passaggio alla copia ha funzionato attorno a questo facendo queste copie invece di spostarle se non fosse possibile generare il costruttore di movimento.

Ma dal momento che = default significa "fare ciò che si farebbe normalmente", include anche questo comportamento di risoluzione di sovraccarico speciale che ignora il costruttore di spostamento implicitamente eliminato.

Problemi correlati