简体   繁体   English

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

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

EDIT2: EDIT2:

To clarify: 澄清:

This question originated from a problem that actually had nothing to do with default parameters themselves, but copy- and move-constructors. 这个问题源于一个实际上与默认参数本身无关的问题,而是复制和移动构造函数。 I accepted the answer that actually answers the question (so if you are here because of the question title, read it) and will explain why it didn't work for me initially. 我接受了实际回答问题的答案(所以如果你因为问题标题而来到这里,请阅读它)并解释为什么它最初对我不起作用。

What was the problem? 出了什么问题?

So the problem, as described under "EDIT:", is actually fairly simple: 因此,如“编辑:”中所述,问题实际上非常简单:

An assignment to a class containing a std::vector<std::unique_ptr<T>> will break compilation in VisualStudio 2013 (not tested with other versions) and the error messages are extremely cryptic. 对包含std::vector<std::unique_ptr<T>>的类的赋值将破坏VisualStudio 2013中的编译(未经其他版本测试),并且错误消息非常神秘。

Assumptions in the comments were that the VC compiler had a bug and tried to call a copy constructor which didn't exist. 评论中的假设是VC编译器有一个bug并试图调用一个不存在的拷贝构造函数。

Shit, what now? 妈的,现在怎么样?

This assumption was in fact true, but not in the sense I first understood it. 这个假设实际上是正确的,但不是我第一次理解它。

Actually, the VCC does in fact try to call the move constructor of MyClass , which it does implicitly define. 实际上,VCC 确实试图调用MyClass的move构造函数,它隐式定义了它。 But , and this is where the problem lies, it doesn't define it correctly : 但是 ,这就是问题所在,它没有正确定义它:

When defining the move constructor MyClass(MyClass && a) explicitly, we can actually imitate the behaviour of the compiler by writing our code like this: 在显式定义移动构造函数MyClass(MyClass && a) ,我们实际上可以通过编写如下代码来模仿编译器的行为:

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

Using this code generates the exact same error messages as using the implicit definition, and I guess you can immediately see what's wrong here: this move constructor actually tries to call the copy constructor of foos_ , which of course isn't possible, because it in turn can't call a copy constructor for its contents, as those are of type std::unique_ptr which doesn't have a copy constructor for obvious reasons. 使用此代码生成使用隐式定义完全相同的错误消息 ,我猜你可以立即看到这里有什么问题:这个移动构造函数实际上试图调用foos_的复制构造foos_ ,这当然是不可能的,因为它在turn无法为其内容调用复制构造函数,因为它们的类型为std::unique_ptr ,由于显而易见的原因, 它没有复制构造函数。

When instead using this code, 而当使用此代码时,

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

everything works out perfectly fine, because now the move constructor of std::vector is called and thus the move constructor for its contents. 一切都很好,因为现在调用std::vector的移动构造函数,因此调用其内容的移动构造函数。

So who's to blame? 那么谁应该受到责备呢?

Possibility 1: 可能性1:

It is in fact a compiler-bug and originates from a template resolving issue. 它实际上是一个编译器错误,起源于模板解决问题。

The compiler wants to implicitly define a move-constructor if needed, and it does so if there are non-copyable types in the class definition and if an assignment to that class is ever made in the code. 编译器希望在需要时隐式定义移动构造函数,如果类定义中存在不可复制的类型,并且在代码中进行了对该类的赋值,则它会这样做。

If these two conditions are satisfied, it proceeds to define the move-constructor, but now doesn't seem to care about the actual type of the std::vector template, only about the class itself, which does indeed define a copy constructor, so the VCC tries to use it, which fails because of the missing copy constructor in std::unique_ptr`. 如果满足这两个条件,它继续定义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

Or, it just skips the definition of the move-constructor entirely and tries to use the copy-constructor, which leads to the same error. 或者,它只是完全跳过move-constructor的定义并尝试使用copy-constructor,这会导致相同的错误。

Possibility 2: 可能性2:

Something fishy in the Microsoft STL implementation. Microsoft STL实现中有些可疑。 This is only a clue and I couldn't explain how it worked exactly, but it seems to be a possibility to me regardless. 这只是一个线索,我无法解释它是如何工作的,但无论如何我似乎都有可能。

How to avoid this mess? 如何避免这种混乱?

Easy, define your own move constructor as shown above. 很容易,定义你自己的移动构造函数,如上所示。


EDIT: 编辑:

It seems to come down to one particular problem, the original answer is posted below. 它似乎归结为一个特定问题,原始答案发布在下面。

In Visual Studio (2013), create a fresh Win32 console application, don't change any settings and make this your main .cpp : 在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;
}

Trying to compile it will result in the following error (It definitely works with gcc!): 尝试编译它将导致以下错误(它肯定适用于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>          ]

Suppose I have a constructor like this: 假设我有一个像这样的构造函数:

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

With this simple setup, everything compiles fine. 通过这种简单的设置,一切都很好。 A call to this constructor like MyClass(vector<unique_ptr<Foo>>); 调用此构造函数,如MyClass(vector<unique_ptr<Foo>>); succeeds and behaves as expected. 成功并按预期行事。 But I'd like to have foos as a default parameter. 但我想将foos作为默认参数。

How can I achieve a default value for foos ? 如何实现foos的默认值?

This is what I came up with: 这就是我想出的:

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

But unfortunately, this doesn't work. 但不幸的是,这不起作用。 I don't know why, it would be nice if somebody could shed some light on this. 我不知道为什么,如果有人能够对此有所了解,那就太好了。

Next two tries, which are workarounds, not actual default parameters: 接下来两次尝试,这是解决方法,而不是实际的默认参数:

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

Don't work either. 也不要工作。 Both these approaches lead to an error message from the compiler and a lengthy output which most interesting part is this: 这两种方法都会导致编译器发出错误消息,并且输出冗长,其中最有趣的部分是:

c:\\users\\ username \\source\\repos\\myProject\\myProject\\MyClass.h(47) : see reference to class template instantiation c:\\ users \\ username \\ source \\ repos \\ myProject \\ myProject \\ MyClass.h(47):参见类模板实例化的引用

Where the 47 is the line number of the actual vector definition in MyClass : 其中47是MyClass实际向量定义的行号:

vector<unique_ptr<GameObject>> foos_;

So my guess would be that this really is about me doing a huge mistake with the initialization. 所以我的猜测是,这真的是关于我在初始化时犯了一个大错误。

Also, I am compiling on VS2013. 另外,我正在编译VS2013。

The whole error: 整个错误:

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>          ]

Write constructor overload which takes no vector at all and initializes your vector by default (To an empty vector): 编写构造函数重载,它根本不带任何向量,并默认初始化向量(到空向量):

MyClass() : foos_{}
{}

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

相关问题 分配std :: vector <std::unique_ptr<T> &gt;到另一个std :: vector <std::unique_ptr<T> &gt; - Assign std::vector<std::unique_ptr<T>> to another std::vector<std::unique_ptr<T>> std :: move或std :: forward,参数为std :: unique_ptr <T> &amp;&amp; - std::move or std::forward with parameter std::unique_ptr<T>&& 返回对 std::vector 的引用范围<std::unique_ptr<t> &gt; </std::unique_ptr<t> - Returning a range of references to a std::vector<std::unique_ptr<T>> 移动std :: vector <std::unique_ptr<T> &gt;到std :: vector <std::shared_ptr<T> &gt; - Move std::vector<std::unique_ptr<T>> to std::vector<std::shared_ptr<T>> 如何将unique_ptr与std :: copy一起使用? - How to use unique_ptr with std::copy? `std :: vector &lt;std :: unique_ptr &lt;T&gt;&gt;`出错 - Error with `std::vector< std::unique_ptr< T > >` 任何更好的替代std :: vector的方法 <std::unique_ptr<T> &gt;? - Any better alternative to std::vector<std::unique_ptr<T>>? 调整std :: vector <std :: unique_ptr <T >>的大小 - Performance of resizing std::vector<std::unique_ptr<T>> 如何在结构上使用 std::unique_ptr? - How to use std::unique_ptr on a struct? 我应该使用std :: vector的std :: unique_ptr吗 <T[]> 如果内存稀疏并且我不会调整大小 - Should i use std::vector of std::unique_ptr<T[]> if memory is sparse and i'm not going to resize
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM