std::unique_ptr 在 GCC 中工作,但在 Visual Studio 中无法编译

std::unique_ptr works in GCC but won't compile in Visual Studio

这花了我一段时间,但我终于构建了一个最小的示例来说明我遇到的问题。

#include <memory>
#include <vector>

class Thing
{
};

class Box
{
public:
  std::vector<std::unique_ptr<Thing>> Things;
  static Box MakeBox() {Box b; return b;}
};

我的真实程序显然比这个复杂很多

GCC 4.8.3 愉快地编译了它。它还编译了真正的应用程序,完美运行。

Visual Studio 2012 坚持 此代码不正确,在 vc\include\xmemory0 的第 606 行给我错误 C2248。如果我浏览几英里的编译器输出,我会发现 真正的 错误源是上例中的第 11 行。 (定义Things.的那一行)VS也拒绝编译我的真实应用,同样的错误。

那么,这段代码正确与否?如果它不正确,那么为什么 GCC 会接受它呢?以及如何使其正确?如果正确,那为什么VS编译不出来呢?有什么方法可以无条件地 force VS 实际编译我的程序吗?


VS 的输出:

1>------ Build started: Project: TestUniquePtr, Configuration: Debug Win32 ------
1>  Main.cpp
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(606): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1>          with
1>          [
1>              _Ty=Thing
1>          ]
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
1>          with
1>          [
1>              _Ty=Thing
1>          ]
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1>          with
1>          [
1>              _Ty=std::unique_ptr<Thing>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(751) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<Thing>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\type_traits(743) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<Thing>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector(655) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::allocator<std::unique_ptr<Thing>>
1>          ]
1>          d:\projects\c++\testuniqueptr\testuniqueptr\main.cpp(11) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::unique_ptr<Thing>
1>          ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

您的问题不是 std::unique_ptr,而是 std::vector

您的编译器带有旧版本的 std::vector,它要求元素类型是可复制的。

按值 (return b;) 的 return 应该调用向量的移动,但是您的 std::vector 没有实现移动。

std::unique_ptr 可移动但不可复制,因此它不满足在 std::vector 中使用的 C++11 之前的要求...仍然适用于 VC++ 2012.

您最好的选择是使用更新的编译器和标准库。一种支持 std::vector.

上的移动语义

否则,您可能会通过消除 std::vector 的副本取得一些进展,例如,让 MakeBox 填写输出参数而不是 return 创建新对象。

static void MakeBox(Box& b) { /* fill Things in b provided by caller */ }

虽然这可能是徒劳的,因为每当向量需要增长时,它必须将现有元素重新定位到新存储,并且在不完整的移动支持下,它会尝试复制这些元素。

问题是 Box 没有移动构造函数,因此返回一个 Box 需要它有一个复制构造函数(它不能,因为 unique_ptr 不可复制)。您所要做的就是为 Box 定义一个移动构造函数:

Box::Box(Box&& other)
  : Things(std::move(other.Things))
{
}

在更新的版本中,编译器将为您生成移动构造函数。