2012-09-28 26 views
8

Tengo un std::vector<Foo> donde Foo es una clase que contiene Foo(Foo&&) noexcept.std :: vector :: erase() no se quiere mover

Agregar objetos al contenedor funciona a la perfección, sin embargo borrarlos usando std::vector::erase(iterator) no lo hace, GCC 4.7 intenta llamar al operador de asignación que he eliminado. El mensaje de error exacto es:

error: el uso de la función de borrado 'Foobar & Foobar operador :: = (const Foobar &)

Editar: Por supuesto std::vector llama al operador de asignación, no la copia constructor (también se puede ver en el mensaje de error). Se corrigió en la descripción, lo siento.

Aquí es ejemplo de código fuente que solicitó:

#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

¿Tiene algún código de demostración? – kennytm

+0

Sin código, es difícil ver cuál es el problema – sehe

+0

Código fuente agregado. :-) – stschindler

Respuesta

11

El problema es que usted no proporcionó un operador de asignación movimiento. Esto es parte del vector Requisitos móviles para algunas funciones.

+0

Oh. Jeje. Acabo de tipear mi propia muestra y agregué automáticamente el operador de asignación de movimiento. Explica por qué funcionó para mí, entonces :) +1 – sehe

+0

¡+1 bien visto! – Walter

+1

El error del compilador lo da todo, no hay 'operador =' adecuado. – Puppy

2

no podía reproducirlo. Resulta que los buenos hábitos son muy importantes: tenía definido el operador de asignación de movimiento.

vivo en 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

En realidad es una muy buena idea, sin embargo, 'erase()' no le gusta el iterador de movimiento, dice que no hay una llamada de función coincidente para 'std :: move_iterator <...>'. – stschindler

+1

Acabo de notar y actualicé el código. Resulta que al "inventar" la muestra duplicada definí automáticamente el operador de asignación de movimiento, como sugiere @DeadMG. Hábitos ... – sehe

+0

Hehe, interesante. Muchas gracias, porque el operador de asignación de movimiento también tiene perfecto sentido. – stschindler

1

respuesta de DeadMG es excelente, sin embargo me gustaría promover otra forma de escribir el operador de asignación:

struct Foo { 
    Foo() {} 

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

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

Dado que se requiere un nuevo temporal en el inicio del método, el compilador elegir ya sea el copiar o mover el constructor para crear este temporal por sí mismo, y no tiene que escribir un operador de asignación de copia Y un operador de asignación de movimiento :)

+0

No lo hace de todos modos, porque su clase no se puede copiar. – Puppy

+0

@DeadMG: evitaré ingresar en los detalles de lo que se incumplió automáticamente y lo que se elimina automáticamente ... es demasiado peculiar. –