繁体   English   中英

如何使用std :: vector <unique_ptr<T> &gt;作为默认参数

[英]How to use a std::vector<unique_ptr<T>> as default parameter

EDIT2:

澄清:

这个问题源于一个实际上与默认参数本身无关的问题,而是复制和移动构造函数。 我接受了实际回答问题的答案(所以如果你因为问题标题而来到这里,请阅读它)并解释为什么它最初对我不起作用。

出了什么问题?

因此,如“编辑:”中所述,问题实际上非常简单:

对包含std::vector<std::unique_ptr<T>>的类的赋值将破坏VisualStudio 2013中的编译(未经其他版本测试),并且错误消息非常神秘。

评论中的假设是VC编译器有一个bug并试图调用一个不存在的拷贝构造函数。

妈的,现在怎么样?

这个假设实际上是正确的,但不是我第一次理解它。

实际上,VCC 确实试图调用MyClass的move构造函数,它隐式定义了它。 但是 ,这就是问题所在,它没有正确定义它:

在显式定义移动构造函数MyClass(MyClass && a) ,我们实际上可以通过编写如下代码来模仿编译器的行为:

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

使用此代码生成使用隐式定义完全相同的错误消息 ,我猜你可以立即看到这里有什么问题:这个移动构造函数实际上试图调用foos_的复制构造foos_ ,这当然是不可能的,因为它在turn无法为其内容调用复制构造函数,因为它们的类型为std::unique_ptr ,由于显而易见的原因, 它没有复制构造函数。

而当使用此代码时,

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

一切都很好,因为现在调用std::vector的移动构造函数,因此调用其内容的移动构造函数。

那么谁应该受到责备呢?

可能性1:

它实际上是一个编译器错误,起源于模板解决问题。

编译器希望在需要时隐式定义移动构造函数,如果类定义中存在不可复制的类型,并且在代码中进行了对该类的赋值,则它会这样做。

如果满足这两个条件,它继续定义move-constructor,但现在似乎并不关心std::vector模板的实际类型,只关于类本身,它确实定义了一个复制constructor, so the VCC tries to use it, which fails because of the missing copy constructor in std :: unique_ptr`中constructor, so the VCC tries to use it, which fails because of the missing copy constructor in

或者,它只是完全跳过move-constructor的定义并尝试使用copy-constructor,这会导致相同的错误。

可能性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 \\ username \\ 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>          ]

编写构造函数重载,它根本不带任何向量,并默认初始化向量(到空向量):

MyClass() : foos_{}
{}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM