versiones dev compiler c++ c++11

dev - c++17



El constructor predeterminado impide llamar a emplace_back (1)

Es un error libstdc ++ (edición: reportado como error 69478 ).

Brevemente, std::vector libstdc ++, como relevante aquí, usa std::uninitialized_copy (emparejado con mover iteradores) para mover elementos en la reasignación, que se reduce a std::copy si el tipo es trivial y los tipos de referencia de los iteradores son asignables (Es decir, el operador de asignación que se usaría conceptualmente es utilizable).

Luego, el std::copy para punteros a tipos triviales (o en nuestro caso, un move_iterator envuelve un puntero) se optimiza a su vez en una llamada a memmove junto con una verificación de is_copy_assignable . Por supuesto, esa comprobación es incorrecta en este caso, ya que la uninitialized_copy , junto con los iteradores de movimiento, solo requiere que la cosa se pueda construir.

Cuando no tienes un constructor predeterminado o si el constructor predeterminado está definido por el usuario, entonces la clase no es trivial, por lo que no tocas la ruta del código que desencadena este error.

Parece que agregar un constructor predeterminado impide llamar a emplace_back y genera el mensaje de error: "error de aserción estática: el tipo no es asignable" (gcc 5.3 con -std = c ++ 14). Aquí hay un código simple que ilustra el problema:

class A { public: int a; A() = default; A(int a) { this->a = a; } A(A const & a) = delete; A& operator =(A const & a) = delete; A(A && a) = default; A& operator =(A && a) = default; }; int main() { A a(4); std::vector<A> vec; vec.emplace_back(std::move(a)); // Error: type is not assignable return 0; }

Al eliminar el constructor por defecto, el error desaparece! Además, si se define el constructor predeterminado (incluso si no hace nada), el error también desaparece:

class A { public: int a; A() { } A(int a) { this->a = a; } A(A const & a) = delete; A& operator =(A const & a) = delete; A(A && a) = default; A& operator =(A && a) = default; }; int main() { A b; A a(4); std::vector<A> vec; vec.emplace_back(std::move(a)); // Error gone return 0; }

Parece que "A () = por defecto;" Es lo que está causando el problema. ¿Este comportamiento normal es parte del compilador o es un error?