2011-11-23 37 views
20

Làm cách nào để truy cập vào các thành phần unique_ptr của vùng chứa (thông qua trình lặp) mà không lấy quyền sở hữu khỏi vùng chứa? Khi một người nhận một trình lặp đến một phần tử trong vùng chứa là quyền sở hữu phần tử vẫn còn với vùng chứa? Làm thế nào về khi một dereferences iterator để đạt được quyền truy cập vào unique_ptr? Điều đó có thực hiện một động thái ẩn của unique_ptr không?Lặp lại một container của unique_ptr

Tôi thấy mình đang sử dụng shared_ptr rất nhiều khi tôi cần lưu trữ các phần tử trong vùng chứa (không theo giá trị), ngay cả khi vùng chứa sở hữu khái niệm các phần tử và mã khác chỉ đơn giản là muốn thao tác các phần tử trong vùng chứa. sợ không thể truy cập các phần tử unique_ptr trong vùng chứa mà không có quyền sở hữu được lấy từ nó.

Mọi thông tin chi tiết?

Trả lời

13

Miễn là bạn không cố tạo bản sao của unique_ptr, bạn chỉ có thể sử dụng nó. Bạn sẽ phải "double dereference" trình vòng lặp để nhận giá trị của con trỏ, giống như bạn phải làm với shared_ptr. Dưới đây là một ví dụ ngắn gọn:

#include <vector> 
#include <memory> 
#include <iostream> 

template <class C> 
void 
display(const C& c) 
{ 
    std::cout << '{'; 
    if (!c.empty()) 
     std::cout << *c.front(); 
    for (auto i = std::next(c.begin()); i != c.end(); ++i) 
     std::cout << ", " << **i; 
    std::cout << "}\n"; 
} 

int main() 
{ 
    typedef std::unique_ptr<int> Ptr; 
    std::vector<Ptr> v; 
    for (int i = 1; i <= 5; ++i) 
     v.push_back(Ptr(new int(i))); 
    display(v); 
    for (auto i = v.begin(); i != v.end(); ++i) 
     **i += 2; 
    display(v); 
} 

Nếu bạn làm (vô tình) tạo một bản sao của unique_ptr:

Ptr p = v[0]; 

sau đó bạn sẽ tìm ra tại thời gian biên dịch. Nó sẽ không gây ra lỗi thời gian chạy. Trường hợp sử dụng của bạn là lý do tại sao container<unique_ptr<T>> được tạo. Mọi thứ sẽ chỉ hoạt động, và nếu không, vấn đề sẽ xuất hiện tại thời gian biên dịch thay vì thời gian chạy. Vì vậy, mã đi, và nếu bạn không hiểu lỗi thời gian biên dịch, sau đó đặt một câu hỏi khác trở lại đây.

+0

Được rồi, tôi nghĩ rằng làm rõ mọi thứ cho tôi. Tôi đã có thói quen sử dụng hàm for_each mới với lambda có tham số là phần tử được truyền theo giá trị, KHÔNG bằng tham chiếu, nhưng tôi đoán tôi sẽ phải tham chiếu cho các phần tử unique_ptr nếu tôi muốn tránh một lần thử sao chép/di chuyển. P.S. nếu tôi dereference iterator một lần, và có một tham chiếu đến kết quả đó, tôi giả định này tránh một bản sao cố gắng? Ý tôi là: 'cho (Container :: iterator it = container.begin(); it! = Container.end(); it ++) { unique_ptr & element = &*it; // Không có bản sao nào? } ' Cảm ơn Howard, btw. –

+0

Vâng, tôi nghĩ rằng nó sẽ hoạt động tốt. Mặc dù bạn có thêm '&' trong mã của mình. Nhưng trình biên dịch sẽ cho bạn biết ở đâu. –

+0

Bạn có thể dereference nó vào một: blah & element = ** it; vẫn không có một bản sao, tôi nghĩ vậy. (Có lẽ hữu ích hơn.) –

32

Với auto và phạm vi dựa trên cho-vòng của C++ 11 này trở nên tương đối thanh lịch:

std::vector< std::unique_ptr<YourClass>> pointers; 
for(auto&& pointer : pointers) { 
    pointer->functionOfYourClass(); 
} 

Tham chiếu & đến std::unique_ptr tránh việc sao chép và bạn có thể sử dụng mà không cần uniqe_ptr dereferencing.

+0

Có ai biết nếu có sự khác biệt giữa việc sử dụng 'tự động &' và 'tự động &' trong trường hợp này không? Tài liệu tham khảo này cho thấy double & http://en.cppreference.com/w/cpp/language/range-for, cả hai dường như biên dịch – austinmarton

+0

Câu hỏi hay. Tôi tìm thấy [liên kết này] (http://en.cppreference.com/w/cpp/language/auto) (xem Giải thích/1) cho thấy rằng 'auto &&' có thể hoạt động như lvalue và rvalue tùy thuộc vào bộ khởi tạo. Tôi thích ứng với ví dụ cho phù hợp. – Pascal

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