【问题标题】:Sorting a list of objects holding a vector of unique_ptr对包含 unique_ptr 向量的对象列表进行排序
【发布时间】:2013-04-29 10:12:46
【问题描述】:

以下代码是否应该根据 C++11 产生编译错误(如果是,为什么?)还是 VC11 的问题?

#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>          ]

【问题讨论】:

  • 作为参考,我可以在 Clang 和 GCC 中很好地编译它。所以它要么是你的编译器,要么是你的设置。
  • @chrisaycock 哦,好吧,准备在 Microsoft Connect 上创建另一个 VC11 错误报告...
  • 我宁愿完全放弃它。
  • 微软已经发布了2个vs2012的更新补丁。你都安装了吗?
  • @rohitsan 当然,我使用的是更新 2。

标签: c++ list c++11 vector unique-ptr


【解决方案1】:

这是“VC 的问题”,但这只是因为您误用了 Visual Studio。

VC++ 实现了右值引用,但它实现了编译器生成的移动构造函数/赋值运算符。这意味着,如果你想让一个类型是可移动的,你必须自己写一个。

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

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

【讨论】:

  • 为什么排序列表(不是向量)需要复制任何内容?排序不是应该通过改变双链表节点的“previous”和“next”指针来实现的吗?
【解决方案2】:

问题确实出在 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; } );
}

【讨论】:

  • 我很清楚什么是移动构造函数以及 VC11 不会隐式生成它们的事实。这丝毫不能解释为什么 VC11 在执行 list 的排序时要复制或移动 A 类型的对象。
  • 好吧,那么你可能会在 STL 源代码中找到答案。我明白你的意思。
【解决方案3】:

这是 Visual C++ 2012 的一个问题(Microsoft 在 Connect 上确认:Compile error in C++ code sorting a list of objects holding a vector of unique_ptr),它已在 Visual C++ 2013 中修复。

另外,我想指出一个问题与事实无关,即 Visual C++ 不会隐式生成移动构造函数。如果您在我的原始示例中显式删除 struct 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; });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-24
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多