2016-08-21 80 views
45

是否有規則說明std :: tuple的成員以何種順序銷燬?C++ std :: tuple的銷燬順序

例如,如果Function1返回std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>>Function2,然後可以我確信(當Function2範圍是左側)的ClassB由所述第二構件中提到的實例是由所指的的ClassA實例之前銷燬第一個成員?

std::tuple< std::unique_ptr<ClassA>, std::unique_ptr<ClassB> > Function1() 
{ 
    std::tuple< std::unique_ptr<ClassA>, std::unique_ptr<ClassB> > garbage; 
    get<0>(garbage).reset(/* ... */); 
    get<1>(garbage).reset(/* ... */); 
    return garbage; 
} 

void Function2() 
{ 
    auto to_be_destroyed = Function1(); 
    // ... do something else 

    // to_be_destroyed leaves scope 
    // Is the instance of ClassB destroyed before the instance of ClassA? 
} 
+2

我猜測它主要取決於如何在標準庫中實現'std :: tuple'。 – Arunmu

+3

我找不到指定'std :: tuple'銷燬順序的規範。可能應該提交爲未指定。 – 101010

+1

http://stackoverflow.com/a/27663655/576911 –

回答

33

該標準沒有規定銷燬的順序std::tuple。該§20.4.1/ P1的事實規定:

兩個參數元組的一個實例是類似於用相同的兩種參數的 實例對。

類似這裏不被解釋爲相同,因此它不意味着std::tuple應該有它的參數反破壞秩序。

鑑於std::tuple的遞歸性質,最可能的是破壞順序與其參數的順序一致。

我也基於我對GCC BUG 66699的錯誤報告的假設,在討論中我的上述假設是合理的。

也就是說,std::tuple的銷燬順序是未指定的。

13

隨着鏘3.4我得到兩個std::pair和2元件std::tuple並用克++ 5.3我得到相反的順序這可能主要是由於在libstd遞歸執行std::tuple ++相同的破壞順序。

所以,它基本上歸結爲我在評論中所說的,它是實現定義的。

BUG報告:

評論馬丁Sebor

由於性病::對成員的佈局完全指定,所以是 爲了自己的初始化和銷燬​​的。測試 案例的輸出反映了這個順序。

std:stuple子對象 的初始化(和破壞)的順序不太清楚。至少從 我不清楚如果任何特定的順序是必需的規範。

之所以輸出的std ::元組的libstdC++是反向的std :: 對是因爲實現,其依賴於遞歸 繼承,存儲和構造元組以相反的順序 元素:即存儲最後一個元素的基類被存儲爲 ,並且首先構造,然後是每個派生類(其中每個 存儲最後的第N個元素)。

從標準[20.4.1節],其錯誤記者引用到

1本節的報價描述了元組庫,提供了一個元組類型 作爲類模板的元組,可以是用任何 參數實例化。每個模板參數指定元組中的 元素的類型。因此,元組是異構的,固定大小的值集合。 具有兩個參數 的元組實例化與參數相同的兩個參數 的實例類似。見20.3。針對這在鏈接錯誤作出

的說法是:

描述爲類似並不意味着它們在每 細節是相同的。 std :: pair和std :: tuple是不同的類,每個類都有不同的 要求。如果您認爲在這方面要求相同地表現 (即,讓其子對象在 中定義相同的順序),則需要指向 保證它的具體措詞。

+3

你怎麼知道'std :: pair'元素的銷燬順序是相反的? – deepmax

+2

類似!= idententical。 – 101010

+0

@deepmax基於std :: pair的libcxx和libstd ++的實現。 – Arunmu

52

我會提供了一個生命的教訓我已經學會了,而不是直接回答,在回答您的問題:

如果你可以制定,對多個備選方案,爲什麼一個合理的說法該替代方案應該是標準強制要求的替代方案 - 那麼您不應該假設其中任何都是(即使其中一個碰巧是)。

在元組的上下文中,請善待維護你的代碼的人,不要讓元組的銷燬順序潛在地破壞其他元素的銷燬。這只是一種邪惡......想象一下這個倒黴的程序員需要調試這個東西。事實上,那些可憐的靈魂可能會在幾年後成爲你自己,當你已經忘掉了你今天聰明的把戲。

如果你絕對必須依賴銷燬順序,也許你應該使用一個適當的類來處理元組的元素作爲它的數據成員(你可以寫一個析構函數,明確以什麼順序發生的事情)或其他一些有助於更明確地控制銷燬的安排。

+1

這是一個非常重要的課程!在使用C++進行編程時,這個技巧一直在開發人員的頭腦中。 – hbobenicio

+0

我不太理解這一點。由於C++ 11字符串需要連續存儲。但是有一個合理的論點(在編寫C++ 03時使用的論點)不要求這樣做。或者,如果你對這個例子提出異議,就選擇另一個標準作出判斷的電話,這樣可以合理地進行。那麼我不應該編寫依賴於C++ 11或C++ 14收緊的代碼嗎?或者你的意思是說,如果標準不清楚,那麼不要依靠下一位程序員以同樣的方式吐毛? –

+0

或者對於一個故意愚蠢的例子,有一個合理的論點:std :: vector應該被稱爲std :: dynamic_array,而std :: valarray應該被稱爲std :: vector。但是我認爲在std :: vector這個標準的基礎上編寫代碼是非常合理的:我們不能在不假設的情況下使用它。所以我不認爲我已經理解了你的建議適用於什麼情況;-) –