编辑2:
澄清:
这个问题源于一个实际上与默认参数本身无关的问题,而是复制和移动构造函数。我接受了实际回答问题的答案(因此,如果您因为问题标题而在这里,请阅读它)并将解释为什么它最初对我不起作用。
出了什么问题?
因此,如“编辑:”中所述,问题实际上相当简单:
对包含 a 的类的分配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
调用了移动构造函数,因此调用了其内容的移动构造函数。
那么该怪谁呢?
可能性一:
它实际上是一个编译器错误,源于模板解析问题。
如果需要,编译器希望隐式定义一个移动构造函数,如果类定义中有不可复制的类型,并且如果在代码中对该类进行了赋值,它就会这样做。
如果满足这两个条件,它会继续定义移动构造函数,但现在似乎并不关心std::vector
模板的实际类型,只关心类本身,它确实定义了一个副本constructor, so the VCC tries to use it, which fails because of the missing copy constructor in
std::unique_ptr`。
或者,它只是完全跳过移动构造函数的定义并尝试使用复制构造函数,这会导致相同的错误。
可能性2:
Microsoft STL 实现中的一些可疑之处。这只是一个线索,我无法解释它是如何工作的,但无论如何,这对我来说似乎是一种可能性。
如何避免这种混乱?
很简单,定义你自己的移动构造函数,如上所示。
编辑:
似乎归结为一个特定问题,原始答案发布在下面。
在 Visual Studio (2013) 中,创建一个全新的 Win32 控制台应用程序,不要更改任何设置并将其设为您的 main .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> ]