簡體   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