2010-07-11 43 views
7

Nói rằng tôi có một std::list của class T 's:std :: danh sách <std :: unique_ptr <T>>: đi qua nó xung quanh

std::list<T> l; 

Khi đi qua nó vào chức năng, tôi sẽ sử dụng một tài liệu tham khảo:

someFunction(std::list<T> &l) 

Cách tốt nhất để vượt qua (các phần tử) của std::list của unique_ptr là gì?

std::list< std::unique_ptr<T> > l; 

Như thế này:

someFunction(std::unique_ptr<T> ptr) 

Hoặc này:

someFunction(T* ptr) 

Hoặc này:

someFunction(T &ref) 

Và những gì làm thế nào tôi sẽ gọi nó bằng cách sử dụng std::list 's back() chức năng chẳng hạn? Đây là IMHO tất cả các loại "tương đương", nhưng tôi chắc chắn tôi đang thiếu một cái gì đó ở đây.

Cảm ơn

Trả lời

7

Theo thứ tự tốt nhất để tồi tệ hơn:

  1. someFunction (const T &);
  2. someFunction (T &);
  3. someFunction (const std :: unique_ptr <T> &);
  4. someFunction (std :: unique_ptr <T> &);

Cách đầu tiên là tốt nhất vì nó không sửa đổi đối tượng và nó sẽ hoạt động với đối tượng bất kể bạn phân bổ như thế nào (ví dụ: bạn có thể chuyển sang shared_ptr mà không gặp vấn đề gì).

Số hai cũng sẽ hoạt động bất kể con trỏ thông minh bạn đang sử dụng; tuy nhiên, nó giả định rằng bạn có thể sửa đổi đối tượng, và bất cứ khi nào bạn có thể làm một cái gì đó const, bạn nên.

Cả số 3 và 4 đều cho phép đối tượng được chỉ định bị biến đổi; tuy nhiên, # 3 không cho phép con trỏ thông minh được sửa đổi, trong khi số 4 thì không. Cả hai đều có những bất lợi mà họ buộc việc sử dụng unique_ptr, trong khi hai ở trên nó sẽ làm việc bất kể lớp con trỏ thông minh.

Chuyển giá trị unique_ptr theo giá trị, như bạn có trong một số ví dụ khác không phải là một tùy chọn; một unique_ptr được cho là duy nhất. Nếu bạn đang sao chép nó, hãy cân nhắc sử dụng shared_ptr.

Đối với lần đầu tiên hai, nếu bạn gọi nó trên kết quả của back(), nó sẽ trông giống như:

someFunction(*(lst.back())); // dereference lst.back() before passing it in. 

Đối với hai nước này, nếu bạn gọi nó trên resut lưng(), nó sẽ như thế nào:

someFunction(lst.back()); // pass the smart pointer, not the object to 
          // which the smart pointer currently points. 
+0

Cảm ơn sâu lời giải thích. Vì vậy, không có ngữ nghĩa đặc biệt là cần thiết cho con trỏ thông minh (ngoại trừ dereferencing). Tôi biết về những thứ 'const', nhưng trong trường hợp này tôi cần sửa đổi đối tượng' T' được truyền vào. – rubenvb

1

do không qua unique_ptr theo giá trị, trước hết nó sẽ không biên dịch mà không có một std::move và nếu bạn làm sử dụng std::move nó sẽ rỗng giá trị bạn đã lưu trữ trong số list và bạn sẽ không thể truy cập vào nó nữa.

Điều này là do unique_ptr không thể sao chép được, nó không có một hàm tạo bản sao kiểu unique_ptr::unique_ptr(const unique_ptr<T>& other) thay vào đó nó chỉ có một hàm tạo di chuyển (unique_ptr::unique_ptr(unique_ptr<T>&& source)).

0

unique_ptr và cũng lớp/trường hợp có chứa unique_ptr có thể được sử dụng trong std :: danh sách (và container khác), với điều kiện là họ phải di chuyển constructorclass_name(class_name &&) định nghĩa (mà unique_ptr, tất nhiên, có).

Khi bạn vượt qua xung quanh những yếu tố này, bạn sẽ luôn di chuyển (và không sao chép) họ, vì vậy bạn luôn luôn sử dụng std :: move() trên lvalues, giống như trong
my_list.push_back(std::move(my_element));
điều này làm cho rõ ràng rằng bạn đang chuyển (= di chuyển) phần tử vào danh sách và my_element là "trống" (như empty_ptr trống) sau thao tác đó.

Ví dụ:

typedef std::unique_ptr<uint8_t[]> data_ptr; 

class data_holder 
{ 
private: 
    int something_about_data; 
    data_ptr data; 
public: 
    data_holder(data_ptr && _data) 
     : data(std::move(_data)) 
    {} 

    // hey compiler, please generate a default move constructor for me 
    // despite of present destructor 
    data_holder(data_holder &&) = default; 

    ~data_holder() 
    { 
     // ... 
    } 

    bool is_empty() const { return ! bool(data); } 
} 

// ... 
{ 
    // ... 
    data_holder the_element(data_ptr(new uint8_t[DATA_SIZE])); 

    // move the_element into the_list 
    the_list.push_back(std::move(the_element)); 
    if (the_element.is_empty()) 
     std::cerr << "data_holder 'the_element' is now empty!" << std::endl; 
    // ... 
} 
Các vấn đề liên quan