2013-05-05 41 views
7

Mã sau đây có phải tạo ra lỗi biên dịch theo C++ 11 (nếu vậy tại sao?) Hoặc đó có phải là vấn đề với VC11 không?Sắp xếp danh sách các đối tượng đang nắm giữ một vectơ của 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 tạo ra lỗi biên dịch sau:

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

Để tham khảo, tôi có thể biên dịch điều này tốt trong Clang và GCC. Vì vậy, đó là trình biên dịch của bạn hoặc cài đặt của bạn. – chrisaycock

+0

@chrisaycock Oh well, sẽ tạo một báo cáo lỗi VC11 khác tại Microsoft Connect ... – PowerGamer

+3

Tôi thà bỏ nó hoàn toàn. –

Trả lời

0

Đó là một vấn đề với Visual C++ 2012 (được công nhận bởi Microsoft vào Connect: Compile error in C++ code sorting a list of objects holding a vector of unique_ptr) và nó đã được cố định trong Visual C++ 2013.

Ngoài ra, tôi muốn chỉ ra rằng một vấn đề không có gì để làm với thực tế, rằng Visual C++ không ngầm tạo ra các nhà xây dựng di chuyển. Nếu bạn xóa tất cả các bản sao và di chuyển các hàm tạo trong cấu trúc A (có, nó sẽ làm cho các đối tượng chèn không thể loại A vào danh sách, nhưng đó là bên cạnh điểm) trong ví dụ ban đầu của tôi, mã vẫn không được sao chép hoặc di chuyển bất kỳ đối tượng và các lỗi biên dịch sản phẩm như vậy:

#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

Đó là "một vấn đề với VC", nhưng chỉ bởi vì bạn đang lạm dụng Visual Studio.

VC++ thực hiện tham chiếu giá trị r, nhưng nó thực hiện không triển khai các nhà khai thác di chuyển được tạo bởi trình biên dịch/nhà khai thác gán. Điều đó có nghĩa là, nếu bạn muốn một loại có thể di chuyển được, bạn phải tự viết một cái.

A không phải là loại có thể di chuyển được, do đó, các chức năng khác nhau std::list sẽ cố gắng sao chép chúng. Và họ sẽ thất bại khi họ cố gắng sao chép vector của unique_ptr. Do đó lỗi trình biên dịch.

Nếu bạn muốn các đối tượng nhận biết di chuyển trong VC++, bạn phải tự viết các hàm tạo/phép gán cho chính chúng.

+2

Tại sao sắp xếp danh sách (không phải là vectơ) yêu cầu sao chép bất kỳ thứ gì? Việc phân loại có được cho là được thực hiện bằng cách thay đổi con trỏ "trước" và "tiếp theo" của các nút danh sách được liên kết kép không? – PowerGamer

3

Vấn đề thực sự ở VC11, như it doesn't implement C++11 feature of automatically generating move operations (như đã được đóng đinh bởi Nicol Bolas).

Mã sau biên dịch với VC10 SP1; trong mẫu mã này, hãy di chuyển hàm tạo là một cách rõ ràng được viết (thay vì di chuyển operator=, sử dụng 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

Tôi khá ý thức về những gì constructor di chuyển và thực tế là VC11 không ngầm tạo ra chúng. Điều đó không giải thích được tại sao VC11 muốn sao chép hoặc di chuyển một đối tượng kiểu A trong khi thực hiện sắp xếp một danh sách *. – PowerGamer

+0

Vâng, sau đó bạn có thể tìm thấy câu trả lời trong mã nguồn STL. Tôi hiểu ý của bạn. –

Các vấn đề liên quan