Вставить в вектор, имеющий объекты без конструктора копирования

У меня есть класс, чьи конструкторы копирования явно удалены (потому что A использует указатели внутри, и я не хочу попадать в мелкие ошибки при копировании):

class A {
public:
A(const A&) = delete;
A& operator=(const A&) = delete;

A(const B& b, const C& c);
}

Теперь у меня есть вектор типа vector<A> aVector; и я хочу вставить элементы в него — поэтому я использую emplace_back:

aVector.emplace_back(b, c);

Тем не менее, это не удается скомпилировать с помощью gcc, и я получаю ошибку —

third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:77:3:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:119:41:   required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:260:63:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:283:67:   required from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:410:6:   required from 'void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:102:4:   required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...)

В чем причина этой ошибки и как ее можно исправить, не удаляя удаление конструкторов копирования? Нужен ли мне конструктор перемещения — нужно ли его явно определять?

13

Решение

Вы должны добавить конструктор перемещения — потому что std::vector::emplace_back может сделать перемещение, которое требует конструктора копирования / перемещения. Или просто использовать std::deque,

LIVE DEMO

#include <vector>
#include <deque>
using namespace std;

struct NoCopyNoMove
{
NoCopyNoMove(const NoCopyNoMove&) = delete;
NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
NoCopyNoMove(NoCopyNoMove&&) = delete;
NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;

NoCopyNoMove(int){};
};

struct OnlyMove
{
OnlyMove(const OnlyMove&) = delete;
OnlyMove& operator=(const OnlyMove&) = delete;
OnlyMove(OnlyMove&&) noexcept {}
OnlyMove& operator=(OnlyMove&&) noexcept {}

OnlyMove(int){};
};

int main()
{
deque<NoCopyNoMove> x;
x.emplace_back(1);

vector<OnlyMove> y;
y.emplace_back(1);
}

§ 23.2.3 Таблица 101 — Операции контейнера необязательной последовательности

a.emplace_back(args) […]

требует: T должен быть EmplaceConstructible в X из аргументов За vector, T также должен быть MoveInsertable в X,

20

Другие решения

Ошибка не является ошибкой emplace_back. Чтобы поместить объект в вектор, он должен быть подвижным или копируемым. Если вы фактически запустите код с реализованным конструктором копирования, вы заметите, что он никогда не вызывается. Это запись на cppreference.com
введите описание изображения здесь

Что бы я сделал, чтобы это исправить, это реализовать конструктор перемещения, который делает его компилируемым, и я не вижу никакого реального недостатка в наличии конструктора перемещения. Как и в случае с cctor, конструктор перемещения не будет вызываться в вашем текущем коде.

8

Я столкнулся с этой проблемой с классом внешней библиотеки. Я получал,

"Error C2280 ClassName::ClassName(const ClassName &)': attempting to reference a deleted function"

Я предполагаю, что класс, который я использовал, имел удаленный его конструктор копирования. Я не мог добавить это к любому std контейнеры, которые я знал для своих пользовательских объектов производного класса, которые обернули их объект некоторыми моими помощниками, чтобы помочь с проверками инициализации / ошибок.

Я работал с этим блокатором (рискованный) указатели.

В основном я перешел к этому:

std::vector<ClassName*> names;
ClassName name("arg");
ClassName name_ptr = &name;
names.push_back(name_ptr);

Исходя из этого, первоначально:

std::vector<ClassName> names;
ClassName name("arg");
names.push_back(name);

Интересно сказать, что это был первый раз кодирование на C ++, которое я на самом деле необходимый использовать указатели для неиспользуемых требований использования из-за отсутствия альтернативы. Это заставляет меня беспокоиться, что я могу пропустить что-то фундаментальное в своем собственном коде.

Может быть, есть лучший способ сделать это, но его еще нет в списке ответов на этот вопрос …

отредактируйте для Caveat:

Я должен был упомянуть об этом раньше, спасибо aschepler;
если вы делаете это, и контейнер, который вы используете, переживает объект, «Взрыв, ты мертв.»

0
По вопросам рекламы [email protected]