2017-12-18 99 views
9

Tại sao mã này không hoạt động như tôi nghĩ?Lặp lại trên unique_ptr không tham chiếu, có chứa vectơ, trong vòng lặp phạm vi

for (auto it: *std::make_unique<std::vector<int>>(std::vector<int>({1, 2, 3, 4, 5}))) 
    std::cout << it << std::endl; 

Đối tượng vector bị phá hủy trước khi thực hiện phiên đầu tiên của vòng lặp

+1

Lưu ý rằng C++ 20 cho phép tránh loại lỗ hổng này thông qua "Phạm vi dựa trên câu lệnh với bộ khởi tạo", như được mô tả tại đây: https://herbsutter.com/2017/11/11/ trip-report-fall-iso-c-standards-meeting-albuquerque /. Tức là: bạn sẽ khai báo riêng biệt 'unique_ptr', đảm bảo nó tồn tại cho toàn bộ vòng lặp, sau đó sử dụng dereference của nó làm phạm vi để lặp lại. –

+1

Tại sao không chỉ đơn giản là viết 'cho (tự động nó: {1, 2, 3, 4, 5})'? và đối với các trường hợp phức tạp hơn, tại sao có 'std :: unique_ptr >' thay vì 'std :: vector '. – Jarod42

+0

Vâng, đó là một ví dụ rất giả tạo, thể hiện khu vực có vấn đề nhưng theo một cách phóng đại. :) –

Trả lời

11

Các range-based for loop tương đương với:

{ 
    init-statement 
    auto && __range = range_expression ; 
    ... 
} 

Đối range_expression của bạn, nó sẽ là

auto && __range = *std::make_unique<std::vector<int>>(std::vector<int>({1, 2, 3, 4, 5})); 

Nhưng

Nếu range_expression trả về một tạm thời, tuổi thọ của pin được kéo dài cho đến khi kết thúc vòng lặp, như được chỉ ra bằng cách gắn vào các tài liệu tham khảo rvalue __range, nhưng hãy cẩn thận rằng tuổi thọ của bất kỳ tạm thời trong vòng range_expression không được gia hạn.

Trả lại số std::make_unique trả về là tạm thời std::unique_ptr, sau khi biểu hiện đầy đủ, nó sẽ bị hủy. Điều đó có nghĩa là std::vector được quản lý bởi nó cũng sẽ bị hủy; mặc dù số std::vector nhận được từ số std::unique_ptr tạm thời bị ràng buộc với tham chiếu chuyển tiếp, thời gian tồn tại của nó sẽ không được kéo dài.

Từ C++ 20 bạn có thể làm việc xung quanh bằng cách sử dụng init-statement; chẳng hạn như

for (auto p = std::make_unique<std::vector<int>>(std::vector<int>({1, 2, 3, 4, 5})); auto it : *p) 
    std::cout << it << std::endl; 
+1

Từ trang đó: "Nếu' range_expression' trả về tạm thời, thời gian tồn tại của nó được kéo dài cho đến cuối vòng lặp, như được chỉ ra bằng cách liên kết với tham chiếu rvalue '__range', nhưng hãy cẩn thận rằng tuổi thọ của bất kỳ tạm thời nào trong' range_expression 'không được mở rộng." – 0x5453

+0

đó là đường cú pháp dính, cảm ơn – Daniil

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