2014-10-21 13 views
10

Dopo aver fatto un po 'di ricerche, vedo che C++11 has a defect con allocatori che richiedono che il tipo sia mobile/copiabile. Sono sicuro che questa sia la causa di questo problema, tuttavia sono confuso riguardo al comportamento tra semantica di move cancellata e non dichiarata.Perché la semantica del movimento eliminato causa problemi con std :: vector?

ho il seguente codice che non riesce a compilare sia MSVC12 e Clang:

#include <vector> 

class Copyable 
{ 
public: 
    Copyable() = default; 

    Copyable(Copyable const& other) 
     : m_int(other.m_int) 
    {} 

    Copyable& operator= (Copyable const& other) 
    { 
     m_int = other.m_int; 
     return *this; 
    } 

    Copyable(Copyable&&) = delete; 
    Copyable& operator= (Copyable&&) = delete; 

private: 
    int m_int = 100; 
}; 

int main() 
{ 
    std::vector<Copyable> objects; 
    objects.push_back(Copyable{}); 
} 

Questo non riesce a compilare il MSVC con:

xmemory0(600): error C2280: 'Copyable::Copyable(Copyable &&)' : attempting to reference a deleted function

E sul Clang (live sample):

In entrambi i casi, quando rimuovo il movimento di spostamento eliminato in modo esplicito/assegna metodi, il codice viene compilato. AFAIK quando si dichiarano metodi di assegnazione/costruzione della copia, il compilatore non dichiara implicitamente i membri di spostamento corrispondenti. Quindi dovrebbero essere effettivamente cancellati, giusto? Perché il codice viene compilato quando rimuovo l'eliminazione esplicita di move construct/assign?

Che cosa è una buona soluzione per questo difetto C++ 11 in generale? Non voglio che i miei oggetti siano mobili (ma sono copiabili).

+0

Implementare lo spostamento tramite una copia? –

+0

Inoltre, relativo a: [Perché le funzioni cancellate da C++ 11 partecipano alla risoluzione di sovraccarico?] (Http: // stackoverflow.it/questions/14085620/why-do-c11-deleted-functions-participation-in-overload-resolution) – Nawaz

risposta

14

L'eliminazione di una funzione non equivale a non dichiararla.

Una funzione eliminata viene dichiarata e partecipa alla risoluzione di sovraccarico, ma se si tenta di chiamarla viene generato un errore.

Se non si dichiara il costruttore di movimento, il compilatore non ne creerà uno mentre si crea un costruttore di copie. La risoluzione del sovraccarico su un valore di rvalore troverà il tuo costruttore di copia, che probabilmente è quello che desideri.

Quello che hai detto con il tuo foo(foo&&)=delete era "se qualcuno cerca di spostare costruisce questo oggetto, genera un errore".

posso illustrare la differenza qui:

void do_stuff(int x) { std::cout << x << "\n"; } 
void do_stuff(double) = delete; 

void do_stuff2(int x) { std::cout << x << "\n"; } 
//void do_stuff2(double) = delete; 

int main() { 
    do_stuff(3); // works 
    //do_stuff(3.14); // fails to compile 
    do_stuff2(3); // works 
    do_stuff2(3.14); // works, calls do_stuff2(int) 
} 

l'unica parte con il problema di cui sopra, che lo rende un po 'più di confusione è che funzioni membro speciali vengono creati automaticamente o meno in base al largo regole leggermente arcane.

10
Copyable(Copyable&&) = delete; 
Copyable& operator= (Copyable&&) = delete; 

A meno che non sei un esperto di semantica spostare (e intendo, davvero informati), non eliminare i membri mossa speciale. Non farà quello che vuoi. Se rivedi il codice di qualcun altro che ha fatto ciò, chiamalo. La spiegazione deve essere davvero solida, e non "perché non voglio che il tipo si muova".

Proprio non farlo.

Il modo corretto di fare ciò che si desidera è semplicemente dichiarare/definire i membri della copia. I membri del movimento verranno inibiti implicitamente (non eliminati, ma in realtà non presenti). Basta scrivere C++ 98/03.

Per ulteriori dettagli, see this answer.

+1

+1 questo è il consiglio pratico che è difficile da trovare anche se ci sono molti riferimenti utili là fuori. –

+2

Che ne dici di scrivere un piccolo libro con tutte queste cose meravigliose (spostare la semantica, passare i parametri, design della classe, date, permutazioni e discussioni) che hai messo insieme qui su SO (e usato in libC++) nel corso degli anni? Come afferma correttamente @ShafikYaghmour, è tutto molto difficile da trovare e disperso. – TemplateRex

+0

@TemplateRex: Alla ricerca del tempo ... –

Problemi correlati