Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a list of objects holding a vector of unique_ptr

Is the following code supposed to produce compilation error according to C++11 (if so why?) or is it a problem with 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 produces the following compilation error:

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>          ]
like image 956
PowerGamer Avatar asked May 05 '13 14:05

PowerGamer


3 Answers

It's "a problem with VC", but only because you're misusing Visual Studio.

VC++ implements r-value references, but it does not implement compiler-generated move constructors/assignment operators. Which means that, if you want a type to be moveable, you must write one yourself.

A is not a moveable type, so the various std::list functions will attempt to copy them. And they'll fail when they try to copy a vector of unique_ptr. Hence the compiler error.

If you want move-aware objects in VC++, you must write move constructors/assignments for them yourself.

like image 84
Nicol Bolas Avatar answered Oct 23 '22 05:10

Nicol Bolas


The problem is really in VC11, as it doesn't implement C++11 feature of automatically generating move operations (as already nailed by Nicol Bolas).

The following code compiles with VC10 SP1; in this code sample, move constructor is explicitly written (instead for move operator=, the copy-and-swap idiom is used).

#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; } );
}
like image 3
Mr.C64 Avatar answered Oct 23 '22 05:10

Mr.C64


It was an issue with Visual C++ 2012 (acknowledged by Microsoft on Connect: Compile error in C++ code sorting a list of objects holding a vector of unique_ptr) and it was already fixed in Visual C++ 2013.

Also, I'd like to point out that an issue had nothing to do with the fact, that Visual C++ does not implicitly generate move constructors. If you explicitly delete all copy and move constructors in struct A (yes, it will make impossible inserting objects of type A into the list, but that is beside the point) in my original example the code still is not supposed to copy or move any objects and as such produce compilation errors:

#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; });
}
like image 1
PowerGamer Avatar answered Oct 23 '22 06:10

PowerGamer