2013-01-23 43 views
9

Tôi muốn có một vectơ con trỏ tới các đối tượng trong lớp của tôi. Để tránh làm cho một destructor cho nó tôi muốn sử dụng std::unique_ptr, như các đối tượng được tạo ra/sở hữu/destructed trong lớp học của tôi, nhưng tôi có một lỗi biên dịch tôi không thể hiểu được. mã tiếp theo sẽ đóng vai trò như một mẫu ngắn cho vấn đề của tôi:Cách sử dụng chính xác của std :: unique_ptr trong khi đẩy vào std :: vector

std::unique_ptr<int> createPtr(int value) 
{ 
    std::unique_ptr<int> ptr(new int(value)); 
    return ptr; 
}; 

int main() 
{ 
    std::vector<std::unique_ptr<int>> vec; 
    vec.push_back(createPtr(1)); 

    std::unique_ptr<int> ptr = createPtr(2); 
    vec.push_back(ptr);//error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
} 

bạn có thể vui lòng giải thích cho tôi tại sao tôi nhận được lỗi này và cách sử dụng chính xác cho std::unique_ptr là gì?

+1

Điểm lưu trữ con trỏ tới 'int' thay vì giá trị trong vector là gì? –

+0

Nếu bạn đang dự tính 'std :: unique_ptr <>', thì bạn có thể làm * không * có một "vectơ của các đối tượng", nhưng là "vectơ của con trỏ tới các đối tượng". Nếu bạn có một "vectơ vật thể", thì sự hủy diệt sẽ tự động xảy ra một cách chính xác. –

+0

@TadeuszKopec Hãy đọc câu hỏi – Felics

Trả lời

12

Xem xét vec.push_back(). Nó có hai quá tải mất const std::unique_ptr<int>& hoặc std::unique_ptr<int>&&. Quá tải đầu tiên có thể không bao giờ được sử dụng. Điều này là do vector<> yêu cầu loại có thể gán hoặc có thể di chuyển (bổ sung C++ 11). 'Khả năng chuyển nhượng' ngụ ý sao chép. push_back(const T&) sẽ cố gắng sao chép (gán) giá trị gửi đến không gian mới ở cuối vùng chứa. std::unique_ptr<> đại diện cho một tài nguyên được sở hữu bởi một chủ sở hữu duy nhất. Bằng cách sao chép nó (con trỏ) nhiều chủ sở hữu sẽ có mặt. Do đó, unique_ptr không thể sao chép được.

Đã nói hết, bạn chỉ có thể sử dụng quá tải T&&.

createPtr() trả về std::unique_ptr<int>, nhưng vì đây là kết quả tạm thời (hàm trả về giá trị), nó được coi là tham chiếu rvalue (ngầm). Đó là lý do tại sao điều này có thể được sử dụng.

ptr chỉ là một std::unique_ptr<int> mà là một tài liệu tham khảo giá trị trái (không có vấn đề nếu bạn đặt & & bên cạnh nó, như tên rvalues ​​vẫn được coi là lvalues). Lvalue không bao giờ được chuyển đổi hoàn toàn thành rvalue (hoàn toàn không an toàn). Nhưng về cơ bản bạn có thể nói với trình biên dịch "Ok, bạn có thể lấy đối tượng mà tôi truyền cho bạn, và tôi hứa tôi sẽ không mong đợi đối số được giữ nguyên" bằng cách sử dụng std::move().

14

Hoặc:

vec.push_back(std::move(ptr)); 

Hoặc:

vec.emplace_back(createPtr(2)); 
+1

Nó giải quyết được vấn đề, nhưng bạn có thể giải thích vấn đề không? – Felics

+7

@Felics Vấn đề là 'unique_ptr' không cho phép xây dựng bản sao, vì vậy cố gắng' push_back' 'ptr' không thành công vì nó cố gắng gọi hàm tạo bản sao.Tuy nhiên, hàm tạo di chuyển có thể truy cập được, và cả hai giải pháp của Kerrek đều gọi nó thay vì hàm tạo bản sao. – Praetorian

+0

@Praetorian Thế còn 'emplace_back' thì sao? – 0x499602D2

2

Bạn có một unique_ptr:

std::unique_ptr<int> ptr = createPtr(2); 

Bây giờ bạn đặt một bản sao của nó trong vector:

vec.push_back(ptr); 

Bây giờ bạn có hai unique_ptr s với cùng giá trị. Nếu điều đó được cho phép thì nó sẽ không phải là duy nhất.

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