2012-03-08 36 views
40

Tôi cố gắng để khởi một std::vector<std::unique_ptr<std::string>> trong một cách mà là tương đương với một ví dụ từ Bjarne Stroustrup's C++11 FAQ:Khởi container của unique_ptrs ra khỏi danh sách khởi tạo không thành công với GCC 4.7

using namespace std; 
vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} }; // fails 
unique_ptr<string> ps { new string{"42"} }; // OK 

tôi có thể thấy không có lý do tại sao cú pháp này nên thất bại . Có điều gì sai trái với cách khởi tạo vùng chứa này không?
Thông báo lỗi trình biên dịch là rất lớn; phân đoạn có liên quan tôi tìm thấy bên dưới:

/usr/lib/gcc-snapshot/lib/gcc/i686-linux-gnu/4.7.0/../../../../include/c++/4.7.0 /bits/stl_construct.h:77:7: error: no matching function for call to 'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'

Cách khắc phục lỗi này là gì?

+3

Đó là chọn đầu vào của biến lặp ctor – PlasmaHH

+0

Rất giống với http://stackoverflow.com/a/9504162/841108 –

+0

@PlasmaHH Trong mã thực tế của tôi, tôi có nhiều mục trong danh sách khởi tạo, vì vậy tôi không tin đây là vấn đề. – juanchopanza

Trả lời

47

unique_ptr hàm tạo là explicit. Vì vậy, bạn không thể tạo một cách ngầm với từ new string{"foo"}. Nó cần phải là một cái gì đó như unique_ptr<string>{ new string{"foo"} }.

nào đưa chúng ta đến đây

vector<unique_ptr<string>> vs { 
    unique_ptr<string>{ new string{"Doug"} }, 
    unique_ptr<string>{ new string{"Adams"} } 
}; 

Tuy nhiên nó có thể bị rò rỉ nếu một trong số các nhà thầu thất bại. Đó là an toàn hơn để sử dụng make_unique:

vector<unique_ptr<string>> vs { 
    make_unique<string>("Doug"), 
    make_unique<string>("Adams") 
}; 

Nhưng ... initializer_list s luôn thực hiện các bản sao, và unique_ptr s không copyable. Đây là một cái gì đó thực sự gây phiền nhiễu về danh sách khởi tạo. Bạn có thể hack around it hoặc dự phòng để khởi tạo với các cuộc gọi đến emplace_back.

Nếu bạn đang thực sự quản lý string s với con trỏ thông minh và nó không chỉ cho ví dụ, sau đó bạn có thể làm tốt hơn: chỉ cần thực hiện một vector<string>. std::string đã xử lý các tài nguyên mà nó sử dụng.

+0

@Xeo, thực sự, http://stackoverflow.com/questions/6804216/how-to-initialize-a-container-of-noncopyable-with-initializer-list – juanchopanza

+0

+1 cho các liên kết! Và không, tôi không thực sự quan tâm về việc tạo một vectơ của unique_ptrs thành chuỗi Nó chỉ là ví dụ từ các câu hỏi thường gặp – juanchopanza

+5

Ví dụ đầu tiên sẽ không bị rò rỉ, trong danh sách khởi tạo là một điểm chuỗi (trong thuật ngữ mới, hơi cồng kềnh hơn , trong '{a, b}', 'a' được giải trình tự trước' b'), xem C++ 11 §8.5.4/4. Mặc dù vậy, bạn nên sử dụng 'make_unique', –

2

Sau khi "sửa chữa" ví dụ của bạn:

#include <vector> 
#include <memory> 
#include <string> 

int main() 
{ 
    std::vector<std::unique_ptr<std::string>> vs = { { new std::string{"Doug"} }, { new std::string{"Adams"} } }; // fails 
    std::unique_ptr<std::string> ps { new std::string{"42"} }; // OK 
} 

tôi đã thông báo lỗi rất rõ ràng:

error: converting to 'std::unique_ptr<std::basic_string<char> >' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = std::basic_string<char>, _Dp = std::default_delete<std::basic_string<char> >, std::unique_ptr<_Tp, _Dp>::pointer = std::basic_string<char>*]' 

lỗi này cho rằng nó không phải là có thể sử dụng contructor rõ ràng các 's unique_ptr.

+6

Aaaand ... thông báo lỗi đó cho chúng tôi biết không có gì. * Tại sao * là nó không thể sử dụng ctor rõ ràng? – Xeo

+0

@Xeo - phần nào công việc đó * rõ ràng * gọi cho ctor? Có thể có một cuộc gọi tiềm ẩn ở đó, nhưng điều đó bị cấm. – Flexo

+3

Ngữ nghĩa của một unique_ptr là nó không thể được sao chép, đó là lý do các nhà xây dựng bị xóa. Nhưng không nên 'std :: vector' được di chuyển-nhận thức và do đó, có thể di chuyển từ một tạm thời để vector? – hirschhornsalz

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