2012-09-28 10 views
8

Ho uno std::vector<Foo> dove Foo è una classe contenente Foo(Foo&&) noexcept.std :: vector :: erase() non si desidera spostare

L'aggiunta di oggetti al contenitore funziona in modo impeccabile, tuttavia non cancellandoli utilizzando std::vector::erase(iterator), GCC 4.7 tenta di chiamare l'operatore di assegnazione che ho eliminato. Il messaggio di errore esatto è:

errore: uso della funzione cancellato 'Foobar & Foobar :: operator = (const Foobar &)

Edit: Naturalmente std::vector chiama l'operatore di assegnazione, non la copia costruttore (lo puoi vedere anche nel messaggio di errore). Risolto problema nella descrizione, mi dispiace.

Ecco esempio di codice sorgente come richiesto:

#include <vector> 

class Foo { 
    public: 
     Foo() {} 
     Foo(Foo&& other) noexcept {} 

     Foo(const Foo&) = delete; 
     Foo& operator=(const Foo&) = delete; 
}; 

int main() { 
    std::vector<Foo> v; 

    v.push_back(Foo{}); 
    v.erase(v.begin()); 
} 
+1

Hai qualche codice demo? – kennytm

+0

Senza codice, è difficile capire quale sia il problema. Codice sorgente aggiunto. – sehe

+0

. :-) – stschindler

risposta

11

Il problema è che non è stato fornito un operatore di assegnazione mossa. Questo fa parte del vettore Requisiti mobili per alcune funzioni.

+0

Oh. Hehe. Ho appena inserito il mio campione e aggiunto automaticamente l'operatore di assegnazione del movimento. Spiega perché ha funzionato per me quindi :) +1 – sehe

+0

+1 ben individuato! – Walter

+1

L'errore del compilatore dà tutto, nessun operatore 'appropriato ='. – Puppy

2

non ho potuto riprodurla. Risulta che le buone abitudini sono molto importanti: ho definito l'operatore di spostamento dell'asse.

Live GCC 4.7.2: http://liveworkspace.org/code/36c600c285f2c91649fd4f73784c2c00

#include <iostream> 
#include <vector> 

struct Foo 
{ 
    Foo() {} 

    Foo(Foo const&) = delete; 
    Foo(Foo&&) throw() { } 

    Foo& operator=(Foo const&) = delete; 
    Foo& operator=(Foo&&) throw() { return *this; } 
}; 

int main(int argc, char* args[]) 
{ 
    std::vector<Foo> v; 
    v.emplace_back(); 
    v.emplace_back(); 
    v.emplace_back(); 
    v.emplace_back(); 

    auto it = v.begin(); 
    it++; 
    v.erase(it); 
} 
+0

In realtà una buona idea, tuttavia 'cancella()' non piace l'iteratore di spostamento, dice che non c'è una chiamata di funzione corrispondente per 'std :: move_iterator <...>'. – stschindler

+1

Ho appena notato e aggiornato il codice. Si scopre che nell '"inventare" il campione di replica ho definito automaticamente l'operatore di assegnazione del movimento, come suggerisce @DeadMG. Abitudini ... – sehe

+0

Hehe, interessante. Grazie mille, anche l'operatore incaricato del trasloco ha perfettamente senso. – stschindler

1

risposta di DeadMG è eccellente, però mi piacerebbe promuovere un altro modo di scrivere l'operatore di assegnazione:

struct Foo { 
    Foo() {} 

    Foo(Foo const&) = delete; 
    Foo(Foo&&) throw() { } 

    Foo& operator=(Foo) throw() { return *this; } 
}; 

Dal momento che hai bisogno di una nuova temporanea all'inizio del metodo, il compilatore scegliere sia la copia o sposta costruttore per creare questo temporaneo da solo, e non devi scrivere sia un operatore di assegnazione delle copie AND un operatore di assegnazione dello spostamento :)

+0

Non lo fa comunque, perché la sua classe è non copiabili. – Puppy

+0

@DeadMG: eviterò di inserire i dettagli di ciò che è automaticamente predefinito e ciò che viene automaticamente eliminato ... è troppo bizzarro. –