如何使用std::vector>作为默认参数?

时间:2022-10-07 18:54:55

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 <:unique_ptr> >将在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. But, and this is where the problem lies, it doesn't define it correctly:

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

When defining the move constructor MyClass(MyClass && a) explicitly, we can actually imitate the behaviour of the compiler by writing our code like this:

当我们明确地定义move构造函数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_试图调用拷贝构造函数,这当然是不可能的,因为它将不能调用拷贝构造函数的内容,这些都是类型的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的move构造函数::调用vector,从而为其内容移动构造函数。

So who's to blame?

Possibility 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 copyconstructor, so the VCC tries to use it, which fails because of the missing copy constructor instd::unique_ptr`.

如果满足这两个条件,它继续定义move-constructor,但现在似乎并不关心的实际类型std::向量模板,只有类本身,这确实定义copyconstructor,VCC试图使用它,不能因为那个失踪的拷贝构造函数instd::unique_ptr’。

Or, it just skips the definition of the move-constructor entirely and tries to use the copy-constructor, which leads to the same error.

或者,它完全跳过了构造函数的定义,并尝试使用复制构造函数,这导致了相同的错误。

Possibility 2:

Something fishy in the Microsoft STL implementation. This is only a clue and I couldn't explain how it worked exactly, but it seems to be a possibility to me regardless.

微软STL实现中的可疑之处。这只是一条线索,我无法解释它到底是如何运作的,但无论如何,这似乎是一种可能性。

How to avoid this mess?

Easy, define your own move constructor as shown above.

轻松定义您自己的move构造函数,如上所示。


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控制台应用程序,不要更改任何设置,并将其设置为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;
}

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>>); succeeds and behaves as expected. But I'd like to have foos as a default parameter.

有了这个简单的设置,一切都可以编译。调用该构造函数,如MyClass(vector >);成功并按照预期行事。但我希望将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:\用户\用户名\ \ \repos\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>          ]

1 个解决方案

#1


1  

Write constructor overload which takes no vector at all and initializes your vector by default (To an empty vector):

写构造函数重载,它不需要任何向量,默认情况下初始化向量(到空向量):

MyClass() : foos_{}
{}

#1


1  

Write constructor overload which takes no vector at all and initializes your vector by default (To an empty vector):

写构造函数重载,它不需要任何向量,默认情况下初始化向量(到空向量):

MyClass() : foos_{}
{}