Конструктор по умолчанию предотвращает вызов emplace_back
Похоже, что добавление конструктора по умолчанию предотвращает вызов emplace_back
и выдает сообщение об ошибке: "static assertion failed: type не присваивается" (gcc 5.3 с -std = С++ 14). Вот простой код, который иллюстрирует проблему:
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;
}
При удалении конструктора по умолчанию ошибка исчезает! Кроме того, если конструктор по умолчанию определен (даже если он ничего не делает), ошибка также исчезает:
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;
}
Кажется, что "A() = default;" что вызывает проблему.
Это нормальное поведение на части компилятора или это ошибка?
Ответы
Ответ 1
Это ошибка libstdС++ (изменение: сообщено как ошибка 69478).
Вкратце, libstdС++ std::vector
, как уместно здесь, использует std::uninitialized_copy
(в паре с итераторами перемещения) для перемещения элементов при перераспределении, что сводится к std::copy
, если тип тривиален и ссылочные типы итераторов назначаются (т.е. можно использовать оператор присваивания, который был бы концептуально использован).
Затем std::copy
для указателей на тривиальные типы (или в нашем случае, a move_iterator
обертывание указателя) в свою очередь оптимизируется на вызов memmove
в сочетании с проверкой на is_copy_assignable
. Конечно, эта проверка неверна в этом случае, так как uninitialized_copy
, соединенный с итераторами перемещения, требует только того, чтобы вещь была конструктивной.
Если у вас нет конструктора по умолчанию или конструктор по умолчанию определяется пользователем, то класс не является тривиальным, поэтому вы не попадаете в путь кода, который запускает эту ошибку.