2017-12-18 336 views
9

爲什麼不按照我的假設工作?迭代包含向量的解除引用unique_ptr,用於範圍循環

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

的矢量對象執行循環的第一次迭代之前銷燬

+1

注意,C++ 20允許避免經由「基於範圍與初始化語句」這種缺陷的,如下所述:https://herbsutter.com/2017/11/11/行程報告下落-ISO-C-標準的會議阿爾伯克基/。也就是說:你將獨立地聲明'unique_ptr',確保它在整個循環中生存,然後使用它的取消引用作爲迭代的範圍。 –

+1

爲什麼不簡單寫'for(auto it:{1,2,3,4,5})'?對於更復雜的情況,爲什麼'std :: unique_ptr >'而不是'std :: vector ''。 – Jarod42

+0

是的,這是一個非常人爲的例子,它展示了問題領域,但有點誇張的方式。 :) –

回答

11

range-based for loop等同於:

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

爲了您range_expression,這將是

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

但是

如果range_expression返回一個暫時的,它的壽命被延長,直到循環的結束時,通過結合到右值參考__range所指示的,但要注意,任何臨時的range_expression內的壽命不延伸。

什麼std::make_unique返回的是一個臨時std::unique_ptr,充分表達它會被銷燬後。這意味着它所管理的std::vector也會被銷燬;即使從臨時std::unique_ptr獲得的std::vector綁定到轉發參考,其生存期也不會延長。

從C++ 20開始,你可能會使用init語句;如

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

從那個頁面:「如果'range_expression'返回一個臨時的,它的生命週期被擴展到循環結束,如綁定到右值引用'__range'所指示的那樣,但要注意'range_expression中任何臨時的生命週期'不延長。「 – 0x5453

+0

這是粘性語法糖,謝謝 – Daniil