![](/img/trans.png)
[英]Assign std::vector<std::unique_ptr<T>> to another std::vector<std::unique_ptr<T>>
[英]How to use a std::vector<unique_ptr<T>> as default parameter
這個問題源於一個實際上與默認參數本身無關的問題,而是復制和移動構造函數。 我接受了實際回答問題的答案(所以如果你因為問題標題而來到這里,請閱讀它)並解釋為什么它最初對我不起作用。
因此,如“編輯:”中所述,問題實際上非常簡單:
對包含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
的移動構造函數,因此調用其內容的移動構造函數。
它實際上是一個編譯器錯誤,起源於模板解決問題。
編譯器希望在需要時隱式定義移動構造函數,如果類定義中存在不可復制的類型,並且在代碼中進行了對該類的賦值,則它會這樣做。
如果滿足這兩個條件,它繼續定義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,這會導致相同的錯誤。
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.