Как использовать std :: vector & lt; unique_ptr & lt; T & gt; & gt; как параметр по умолчанию

EDIT2:

Чтобы уточнить:

Этот вопрос возник из-за проблемы, которая на самом деле не имела ничего общего с параметрами по умолчанию, а с конструкторами копирования и перемещения.
Я принял ответ, который на самом деле отвечает на вопрос (поэтому, если вы находитесь здесь из-за названия вопроса, прочитайте его) и объясню, почему он изначально не работал для меня.

В чем была проблема?

Таким образом, проблема, описанная в «EDIT:», на самом деле довольно проста:

Присвоение классу, содержащему std::vector<std::unique_ptr<T>> нарушит компиляцию в VisualStudio 2013 (не тестировалась с другими версиями), а сообщения об ошибках будут крайне загадочными.

Предположения в комментариях заключались в том, что компилятор VC имел ошибку и пытался вызвать конструктор копирования, которого не было.

Дерьмо, что теперь?

Это предположение на самом деле было правдой, но не в том смысле, в котором я впервые его понял.

На самом деле, VCC делает на самом деле попробуйте вызвать конструктор перемещения MyClass, который он неявно определяет. Но, и вот в чем проблема, она не определяет правильно:

При определении конструктора перемещения MyClass(MyClass && a) явно, мы можем фактически имитировать поведение компилятора, написав наш код следующим образом:

MyClass(MyClass && a)
: foos_(a.foos_)
{}

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

Когда вместо этого используется этот код,

MyClass(MyClass && a)
: foos_(std::move(a.foos_))
{}

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

Так кто же виноват?

Возможность 1:

На самом деле это ошибка компилятора, возникшая из-за проблемы с шаблоном.

Компилятор хочет неявно определить конструктор перемещения, если это необходимо, и делает это, если в определении класса есть не копируемые типы и если в коде когда-либо выполняется присвоение этому классу.

Если эти два условия выполняются, он переходит к определению конструктора перемещения, но теперь, похоже, не заботится о реальном типе std::vector шаблон, только о самом классе, который действительно определяет копиюconstructor, so the VCC tries to use it, which fails because of the missing copy constructor inстанд :: unique_ptr`.

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

Возможность 2:

Что-то подозрительное в реализации Microsoft STL. Это всего лишь ключ, и я не могу объяснить, как именно это работает, но мне кажется, что это возможно.

Как избежать этого беспорядка?

Легко, определите свой собственный конструктор перемещения, как показано выше.


РЕДАКТИРОВАТЬ:

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

В Visual Studio (2013) создайте новое консольное приложение Win32, не меняйте никаких настроек и сделайте это своим основным .cpp:

// ConsoleApplication2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <vector>
#include <memory>

class Foo { };

class MyClass
{
public:
MyClass(std::vector<std::unique_ptr<Foo>> foos) :
foos_(std::move(foos))
{};

std::vector<std::unique_ptr<Foo>> foos_;
};

int _tmain(int argc, _TCHAR* argv[])
{
auto test = MyClass(std::vector<std::unique_ptr<Foo>>()); //remove this, and all works fine!
return 0;
}

Попытка скомпилировать приведет к следующей ошибке (она определенно работает с gcc!):

1>  ConsoleApplication2.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(593): error C2280: 'std::unique_ptr<Foo,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
1>          with
1>          [
1>              _Ty=Foo
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(1486) : see declaration of 'std::unique_ptr<Foo,std::default_delete<_Ty>>::unique_ptr'
1>          with
1>          [
1>              _Ty=Foo
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(592) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1>          with
1>          [
1>              _Ty=std::unique_ptr<Foo,std::default_delete<Foo>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<Foo,std::default_delete<Foo>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(572) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<Foo,std::default_delete<Foo>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see reference to class template instantiation 'std::is_empty<_Alloc>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<std::unique_ptr<Foo,std::default_delete<Foo>>>
1>          ]
1>          c:\users\felix\source\repos\infinite whitewursht\infinitewhitewursht\consoleapplication2\consoleapplication2.cpp(18) : see reference to class template instantiation 'std::vector<std::unique_ptr<Foo,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' being compiled
1>          with
1>          [
1>              _Ty=Foo
1>          ]

Предположим, у меня есть такой конструктор:

MyClass(vector<unique_ptr<Foo>> foos) :
foos_(std::move(foos))
{};

С этой простой настройкой все компилируется нормально.
Вызов этого конструктора, как MyClass(vector<unique_ptr<Foo>>); успешно и ведет себя как ожидалось. Но я бы хотел иметь foos в качестве параметра по умолчанию.

Как я могу получить значение по умолчанию для foos?

Вот что я придумал:

MyClass(vector<unique_ptr<Foo>> foos = vector<unique_ptr<Foo>>()) :
foos_(std::move(foos))
{};

Но, к сожалению, это не работает. Я не знаю почему, было бы хорошо, если бы кто-то мог пролить свет на это.

Следующие две попытки, которые являются обходными, а не фактическими параметрами по умолчанию:

MyClass() :
foos_() //or foos_(vector<unique_ptr<Foo>>())
{};

Тоже не работает. Оба этих подхода приводят к сообщению об ошибке от компилятора и длинному выводу, наиболее интересная часть которого такова:

C: \ Users \ имя пользователя \ source \ repos \ myProject \ myProject \ MyClass.h (47): см. ссылку на создание шаблона класса

Где 47 — номер строки фактического определения вектора в MyClass:

vector<unique_ptr<GameObject>> foos_;

Так что я думаю, что это действительно из-за того, что я сделал огромную ошибку с инициализацией.

Также я собираю на VS2013.

Вся ошибка:

GameObject.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(593): error         C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(1486) : see declaration of 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr'
1>          with
1>          [
1>              _Ty=int
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(592) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1>          with
1>          [
1>              _Ty=std::unique_ptr<int,std::default_delete<int>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(723) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<int,std::default_delete<int>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(572) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<int,std::default_delete<int>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see reference to class template instantiation 'std::is_empty<_Alloc>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<std::unique_ptr<int,std::default_delete<int>>>
1>          ]
1>          c:\users\felix\source\repos\infinite whitewursht\infinitewhitewursht\infinitewhitewursht\gameobject.h(47) : see reference to class template instantiation 'std::vector<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' being compiled
1>          with
1>          [
1>              _Ty=int
1>          ]

4

Решение

Напишите перегрузку конструктора, которая вообще не принимает вектор и инициализирует ваш вектор по умолчанию (в пустой вектор):

MyClass() : foos_{}
{}
2

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector