Std::vector emplace_back() для не копируемых конструктивных объектов
Учитывая эту цитату из en.cppreference.com относительно std::vector::emplace_back
"Добавляет новый элемент в конец контейнера. построенный на месте, то есть операции копирования или перемещения не выполняются. Конструктор элемента называется точно таким же аргументы, которые предоставляются функции."
и следующий образец:
#include <vector>
struct A
{
A(int){}
A(A const&) = delete;
};
int main()
{
std::vector<A> vec;
vec.emplace_back(1);
return 0;
}
В строке vec.emplace_back(1);
Отчет Visual Studio 2013/GCC:
ошибка C2280: 'A:: A (const A &)': попытка ссылки на удаленную функцию
ошибка: использование удаленной функции "A:: A (const A &)
Правильно ли ошибка? Можете ли вы объяснить мне, почему?
Ответы
Ответ 1
С++ 11 23.2.1 В таблице 101 указано:
Выражение: a.emplace_back(args)
Тип возврата: void
Семантика операции: добавляет объект типа T
, построенный с помощью std::forward<Args>(args)...
. Требуется: T
должно быть EmplaceConstructible
в X
из args
. Для vector
, T
также должно быть MoveInsertable
в X
.
Ваш A
не выполняет требование MoveInsertable
, так как у вас нет конструктора перемещения и есть только конструктор удаленной копии. С контейнером, отличным от std::vector
, он работает.
Ответ 2
Как и другие функции, которые увеличивают размер вектора, emplace_back
условно перераспределяет вектор (если текущая емкость недостаточно велика). Если это так, то нужно получить существующие элементы из старого массива в новый.
У вашего класса нет конструктора перемещения (некоторые классы имеют сгенерированный компилятором ход, но не этот, потому что вы удалили конструктор копирования). Поэтому код перераспределения должен иметь возможность копировать тип, и он не может.
Конечно, для этого вызова нет старых элементов для копирования, но тем не менее функция emplace_back
не может быть создана.