[英]Why does std::queue use std::dequeue as underlying default container?
[英]Why does default constructor of std::atomic not default initialize the underlying stored value?
由於今天是美國的感恩節,我將成為指定的火雞來問這個問題:
采取像這樣無害的事情。 具有簡單普通舊數據類型(例如 int)的原子:
atomic<int> x;
cout << x;
以上將打印出垃圾(未定義)數據。 鑒於我閱讀的原子構造函數,這是有道理的:
(1) 默認構造函數
使原子對象處於未初始化狀態。 未初始化的原子對象稍后可以通過調用 atomic_init 進行初始化。
感覺像是一個奇怪的委員會決定。 但我相信他們有他們的理由。 但我想不出另一個std::
類,其中默認構造函數會使對象處於未定義狀態。
我可以看到對於沒有默認構造函數並且需要進入atomic_init
路徑的更復雜類型與std::atomic
一起使用有何意義。 但更一般的情況是使用具有簡單類型的原子,用於引用計數、順序標識符值和簡單的基於輪詢的鎖定等場景。 因此,這些類型沒有自己的存儲值“零初始化”(默認初始化)感覺很奇怪。 或者至少,如果不可預測,為什么要有一個默認構造函數。
未初始化的std::atomic
實例會有用的原因是什么。
如P0883中所述,此行為的主要原因是與 C 的兼容性。顯然 C 沒有值初始化的概念; atomic_int i;
不執行初始化。 為了與 C 兼容,等效的 C++ 也必須不執行初始化。 由於 C++ 中的atomic_int
應該是std::atomic<int>
的別名,因此為了完全兼容 C/C++,該類型也必須不執行初始化。
幸運的是, C++20 似乎正在消除這種行為。
未初始化的
std::atomic
實例會有用的原因是什么。
出於同樣的原因,基本的“構建塊”用戶定義類型不應做超出嚴格要求的事情,尤其是在像構造這樣不可避免的操作中。
但我想不出另一個 std:: 類,其中默認構造函數會使對象處於未定義狀態。
所有不需要內部不變量的類都是這種情況。
通用代碼中沒有期望T x;
將創建一個零初始化對象; 但預計它將創建一個可用狀態的對象。 對於標量類型,任何現有對象在其生命周期內都是可用的。
另一方面,預計
T x = T();
將為通用代碼創建一個處於默認狀態的對象,用於普通值類型。 (如果所表示的值有這樣的東西,它通常是一個“零值”。)
原子並不是真正關於值的范圍。 它們旨在為讀取、寫入和復雜操作提供特殊保證; 原子在很多方面不同於其他數據類型,因為沒有根據對該對象的正常賦值定義復合賦值操作。 所以通常的等價物不適用於原子。 您不能像對普通對象那樣對原子進行推理。
您根本無法在原子和普通對象上編寫通用代碼; 這將毫無意義。
(見腳注。)
[腳注:
下面是一篇技術性重要的文字“吐槽”,但對於理解原子對象的構造函數為什么會是這樣並不重要。
它們只是以最深刻的方式遵循不同的語義規則:標准甚至沒有描述的方式,因為標准從未解釋多線程的最基本事實:語言的某些部分被評估為一系列操作取得進展,而其他領域(原子,try_lock ...)則沒有。 事實上,標准的作者顯然甚至沒有看到這種區別,甚至不理解這種二元性。 (請注意,討論這些問題通常會使您的問題和答案遭到否決和刪除。)
這種區別是必不可少的,因為沒有它(同樣,它在標准中沒有出現),零個程序甚至可以具有多線程定義的行為:只有舊式的線程前行為可以在沒有這種二元性的情況下得到解釋。
C++ 委員會不了解 C++ 的症狀是他們認為“無稀有值”是一個額外的特性,而不是語義的重要組成部分(沒有獲得原子的“無稀有”保證承諾順序程序的順序語義更站不住腳)。
--尾注]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.