2013-05-05 92 views
7

下面的代码是否应该根据C++ 11产生编译错误(如果是这样,为什么?),还是VC11有问题?对持有unique_ptr向量的对象列表进行排序

#include <vector> 
#include <list> 
#include <memory> 
struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 
}; 
int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& a1, const A& a2){ return true; }); 
} 

的Visual C++ 2012产生以下编译错误:

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=int 
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=int 
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<int> 
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<int> 
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<int> 
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<int>> 
1>   ] 
1>   d:\test2\test2.cpp(213) : see reference to class template instantiation 'std::vector<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::unique_ptr<int> 
1>   ] 
+0

作为参考,我可以在Clang和GCC编译这很好。所以它不是你的编译器就是你的设置。 – chrisaycock 2013-05-05 14:31:32

+0

@chrisaycock很好,我们将在Microsoft Connect上创建另一个VC11错误报告... – PowerGamer 2013-05-05 14:39:34

+3

我宁愿放弃它。 – 2013-05-05 14:41:08

回答

0

它是用Visual C的一个问题++ 2012(Microsoft在连接承认:Compile error in C++ code sorting a list of objects holding a vector of unique_ptr),它已经被固定在Visual C++ 2013年

另外,我想指出的问题与事实无关,Visual C++不会隐式生成移动构造函数。如果你明确地删除了结构A中的所有拷贝和移动构造函数(是的,在我的原始示例中,将不可能将类型A的对象插入到列表中,但这不是那么重要),代码仍然不应该复制或移动任何对象,并因此产生编译错误:

#include <vector> 
#include <list> 
#include <memory> 
struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 
    A(A&&) = delete; 
    A(const A&) = delete; 
}; 
int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& a1, const A& a2){ return true; }); 
} 
4

这是 “与VC有问题”,但仅仅是因为你滥用的Visual Studio。

VC++实现了r值引用,但它确实执行了而不是实现了编译器生成的移动构造函数/赋值操作符。这意味着,如果你想要一个类型是可移动的,你必须自己写一个类型。

A不是一个可移动的类型,所以各种std::list函数将尝试复制它们。当他们试图复制vectorunique_ptr时,他们会失败。因此编译器错误。

如果你想在VC++中感知移动的对象,你必须自己编写移动构造函数/赋值。

+2

为什么排序列表(而不是向量)需要复制任何东西?不排序是否应该通过更改双链表节点的“上一个”和“下一个”指针来实现? – PowerGamer 2013-05-05 18:51:48

3

这个问题真的出现在VC11中,正如it doesn't implement C++11 feature of automatically generating move operations(正如Nicol Bolas所指出的那样)。

以下代码与VC10 SP1一起编译;在此代码示例中,移动构造函数是明确写入(而不是移动operator=,则使用copy-and-swap idiom)。

#include <algorithm> // for std::swap (for copy-and-swap idiom) 
#include <list> 
#include <memory> 
#include <vector> 

struct A 
{ 
    std::vector<std::unique_ptr<int>> v; 

    A(A&& other) 
     : v(std::move(other.v)) 
    { 
    } 

    A& operator=(A other) 
    { 
     swap(*this, other); 
     return *this; 
    } 

    friend void swap(A& lhs, A& rhs) 
    { 
     using std::swap; 
     swap(lhs.v, rhs.v); 
    } 
}; 

int main() 
{ 
    std::list<A> l; 
    l.sort([](const A& , const A&){ return true; }); 
} 
+1

我很清楚移动构造函数是什么,以及VC11不隐式生成它们的事实。这并不能解释为什么VC11希望在执行* list *排序时复制或移动类型A的对象。 – PowerGamer 2013-05-06 06:38:26

+0

那么你可以在STL源代码中找到答案。我明白你的观点。 – 2013-05-06 09:36:16