Как объявить вектор unique_ptr как элемент данных класса?

Я хотел бы иметь вектор unique_ptr в качестве члена класса, который я создаю.

class Foo {
    [...]

private:
    vector<unique_ptr<Bar>> barList;
}

Но затем я начинаю получать загадочные сообщения об ошибках от компилятора VS2010:

error C2248: 'std::unique_ptr<_Ty>::operator =' : cannot access private member declared in class 'std::unique_ptr<_Ty>'

Наряду с несколькими строками ошибок ниже той, которая погружается в реализацию Microsoft std::_Copy_impl<>...

Я изменил объявление члена на

vector<unique_ptr<Bar>>* barList;

И он компилируется. Но я не могу не задаться вопросом, почему я не могу сделать это так, как я изначально хотел? Для ухмылки я попробовал это, и он отлично работает:

vector<Bar> barList;

Но теперь я теряю удобство unique_ptr. Я хочу свой торт и хочу его съесть!


person Bret Kuhns    schedule 24.01.2012    source источник
comment
Я просматривал stackoverflow.com/questions/8553464/vector -as-a-class-member, и ответ, кажется, думает, что объявление vector, как это сделал я, вполне нормально. Однако по какой-то причине кажется, что при добавлении части unique_ptr возникают незаконные копии.   -  person Bret Kuhns    schedule 24.01.2012
comment
Как выглядят ваши конструктор копирования и оператор присваивания?   -  person Benjamin Lindley    schedule 24.01.2012
comment
Частное задание, но виновником был конструктор копирования. Переключился с unique_ptr на shared_ptr, когда понял, что использую неправильную семантику владения.   -  person Bret Kuhns    schedule 24.01.2012


Ответы (5)


Проблема здесь в том, что где-то ваш код пытается вызвать оператор «копирования-присваивания» Foo.

Это заставляет компилятор попытаться сгенерировать оператор присваивания копирования, который вызывает операторы присваивания копирования всех подобъектов Foo. В конце концов, это приводит к попытке скопировать unique_ptr, что невозможно.

person Mankarse    schedule 24.01.2012
comment
Спасибо за указание на это. Компилятор ввел меня в заблуждение, потому что ошибка ссылалась на объявление члена и не упоминала о нарушении кода, вызывающего копирование. Я полагаю, что это недостаток VS2010, и, надеюсь, он будет исправлен в новых версиях. В моем классе Foo есть конструктор копирования, и я пытался скопировать вектор из исходного Foo. Совместное владение кажется лучшим решением, поэтому переход на shared_ptr помог. - person Bret Kuhns; 24.01.2012
comment
Похоже на ошибку в VS2010. Я получаю эту ошибку, даже если мой код никогда не пытается вызвать присваивание копии. Отключение оператора = с объявлением его закрытым (поэтому =delete не поддерживается) решает проблему. - person tr3w; 20.11.2012

unique_ptr не имеет семантики копирования, поэтому вы не можете использовать какие-либо методы, которые копировали бы содержащийся объект. Вы можете сделать это со ссылками rvalue, используя std::move в местах, где он пытается создать копию. Не видя вашего кода, я не могу сказать, где это будет.

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

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

person Mark B    schedule 24.01.2012
comment
auto_ptr не подчиняется обычной семантике копирования, unique_ptr просто не имеет семантику копирования - person Grizzly; 24.01.2012
comment
Ваши ответы и ответы Манкарсе очень похожи. Его, однако, заставили меня понять, что мне нужно отправиться на охоту на ведьм для оскорбительного кода (ваш ответ коснулся этой проблемы более тонко). Однако вы оба заслуживаете принятого ответа. Спасибо за помощь! - person Bret Kuhns; 24.01.2012

Часто где-то отсутствует std::move(iUniquePtr) (например, при использовании push_back).

person Sonic78    schedule 07.02.2014

Выдержки из www.cplusplus.com

std::unique_ptr::operator=

Назначение unique_ptr Объект получает право собственности на содержимое x, включая хранимый указатель и хранимое средство удаления (вместе с ответственностью за удаление объекта в какой-то момент). Любой объект, принадлежащий объекту unique_ptr до вызова, удаляется (как если бы был вызван деструктор unique_ptr).

Но есть и предупреждение:

На этой странице описывается функция, представленная в последней версии стандарта C++ (2011 г.). Старые компиляторы могут не поддерживать его.

MSVC 2010 определяет operator= как закрытый (не копируемый), но поддерживает метод swap.

person ibre5041    schedule 29.05.2014

Вы не можете использовать unique_ptr в векторе, потому что реализация вектора сильно зависит от оператора присваивания значений, который является закрытым в unique_ptr. Используйте shared_ptr из boost или другую реализацию smart ptr из C++11.

person aambrozkiewicz    schedule 24.01.2012
comment
Контейнеры C++11 необходимы для работы с типами только для перемещения, такими как unique_ptr. - person bames53; 24.01.2012
comment
Я имел в виду то, как он его использовал. Но все же, спасибо, я не знал о emplace_back. - person aambrozkiewicz; 24.01.2012
comment
Вам не нужно использовать emplace_back. Вы можете использовать push_back, если вы даете ему r-значения. - person Benjamin Lindley; 24.01.2012