[英]Is storage for the same content string literals guaranteed to be the same?
下面的代碼安全嗎? 編寫類似於此的代碼可能很誘人:
#include <map>
const std::map<const char*, int> m = {
{"text1", 1},
{"text2", 2}
};
int main () {
volatile const auto a = m.at("text1");
return 0;
}
該映射僅用於字符串文字。
我認為它是完全合法的並且似乎正在工作,但是我從未看到保證在兩個不同的地方使用的文字指針是相同的。 我無法讓編譯器為具有相同內容的文字生成兩個單獨的指針,所以我開始懷疑這個假設是多么堅定。
我只對具有相同內容的文字是否可以有不同的指針感興趣。 或者更正式的,上面的代碼可以除外嗎?
我知道有一種編寫代碼的方法可以確保它有效,我認為上面的方法很危險,因為編譯器可以決定為文字分配兩個不同的存儲,特別是如果它們放在不同的翻譯單元中。 我對嗎?
是否具有完全相同內容的兩個字符串文字是完全相同的對象,是未指定的,並且在我看來最好不依賴。 引用標准:
[lex.string]
16評估字符串文字會產生具有靜態存儲持續時間的字符串文字對象,從上面指定的給定字符初始化。 是否所有字符串文字都是不同的(即,存儲在非重疊對象中)以及是否對字符串文字的連續評估產生相同或不同的對象是未指定的。
如果你想避免std::string
的開銷,你可以編寫一個簡單的視圖類型(或在C ++ 17中使用std::string_view
),它是一個字符串文字的引用類型。 使用它進行智能比較,而不是依賴於文字身份。
標准不保證具有相同內容的字符串文字的地址將是相同的。 事實上, [lex.string] / 16說:
是否所有字符串文字都是不同的(即,存儲在非重疊對象中)以及是否對字符串文字的連續評估產生相同或不同的對象是未指定的。
第二部分甚至說當第二次調用包含字符串文字的函數時,你可能得不到相同的地址! 雖然我從未見過編譯器那樣做。
因此,在重復字符串文字時使用相同的字符數組對象是可選的編譯器優化。 通過安裝g ++和默認編譯器標志,我還發現在同一個翻譯單元中我獲得了兩個相同字符串文字的相同地址。 但是正如您猜測的那樣,如果相同的字符串文字內容出現在不同的翻譯單元中,我會得到不同的內容。
一個相關的有趣點:它也允許不同的字符串文字使用重疊數組。 也就是說,給定
const char* abcdef = "abcdef";
const char* def = "def";
const char* def0gh = "def\0gh";
你可能會發現abcdef+3
, def
和def0gh
都是相同的指針。
此外,關於重用或重疊字符串文字對象的此規則僅適用於與文字直接關聯的未命名數組對象,如果文字立即衰減到指針或綁定到對數組的引用,則使用該規則。 文字也可用於初始化命名數組,如
const char a1[] = "XYZ";
const char a2[] = "XYZ";
const char a3[] = "Z";
這里使用文字對數組對象a1
, a2
和a3
進行初始化,但被認為與實際文字存儲不同(如果這樣的存儲甚至存在)並遵循普通對象規則,因此這些數組的存儲不會重疊。
不,C ++標准沒有這樣的保證。
也就是說,如果代碼在同一個翻譯單元中,那么很難找到一個反例。 如果main()
處於不同的轉換中,則計數器示例可能更容易生成。
如果地圖位於不同的動態鏈接庫或共享對象中,那么幾乎肯定不是這種情況。
volatile
限定符是紅鯡魚。
C ++標准不要求實現去除字符串文字。
當字符串文字駐留在另一個轉換單元或另一個共享庫中時,它需要鏈接器( ld
)或運行時鏈接器( ld.so
)來執行字符串文字重復數據刪除。 他們沒有。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.