相同内容字符串文字的存储是否保证相同?

luk*_*k32 24 c++ storage string-literals language-lawyer

下面的代码安全吗?编写类似于此的代码可能很诱人:

#include <map>

const std::map<const char*, int> m = {
    {"text1", 1},
    {"text2", 2}
};

int main () {
    volatile const auto a = m.at("text1");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该映射仅用于字符串文字.

我认为它是完全合法的并且似乎正在工作,但是我从未看到保证在两个不同的地方使用的文字指针是相同的.我无法让编译器为具有相同内容的文字生成两个单独的指针,所以我开始怀疑这个假设是多么坚定.

我只对具有相同内容的文字是否可以有不同的指针感兴趣.或者更正式的,上面的代码可以除外吗?

我知道有一种编写代码的方法可以确保它有效,我认为上面的方法很危险,因为编译器可以决定为文字分配两个不同的存储,特别是如果它们放在不同的翻译单元中.我对吗?

Sto*_*ica 20

是否具有完全相同内容的两个字符串文字是完全相同的对象,是未指定的,并且在我看来最好不依赖.引用标准:

[lex.string]

16评估字符串文字会产生具有静态存储持续时间的字符串文字对象,从上面指定的给定字符初始化.是否所有字符串文字都是不同的(即,存储在非重叠对象中)以及是否对字符串文字的连续评估产生相同或不同的对象是未指定的.

如果您希望避免开销std::string,可以编写一个简单的视图类型(或std::string_view在C++ 17中使用),它是字符串文字的引用类型.使用它进行智能比较,而不是依赖于文字身份.


asc*_*ler 18

标准不保证具有相同内容的字符串文字的地址是相同的.事实上,[lex.string]/16说:

是否所有字符串文字都是不同的(即,存储在非重叠对象中)以及是否对字符串文字的连续评估产生相同或不同的对象是未指定的.

第二部分甚至说当第二次调用包含字符串文字的函数时,你可能得不到相同的地址!虽然我从未见过编译器那样做.

因此,在重复字符串文字时使用相同的字符数组对象是可选的编译器优化.通过安装g ++和默认编译器标志,我还发现在同一个翻译单元中我获得了两个相同字符串文字的相同地址.但是正如您猜测的那样,如果相同的字符串文字内容出现在不同的翻译单元中,我会得到不同的内容.


一个相关的有趣点:它也允许不同的字符串文字使用重叠数组.也就是说,给定

const char* abcdef = "abcdef";
const char* def = "def";
const char* def0gh = "def\0gh";
Run Code Online (Sandbox Code Playgroud)

你可能会发现abcdef+3,def并且def0gh都是相同的指针.

此外,关于重用或重叠字符串文字对象的此规则仅适用于与文字直接关联的未命名数组对象,如果文字立即衰减到指针或绑定到对数组的引用,则使用该规则.文字也可用于初始化命名数组,如

const char a1[] = "XYZ";
const char a2[] = "XYZ";
const char a3[] = "Z";
Run Code Online (Sandbox Code Playgroud)

这里是数组对象a1,a2a3使用文字进行初始化,但被认为与实际文字存储不同(如果这样的存储甚至存在)并遵循普通对象规则,因此这些数组的存储不会重叠.

  • 我正在考虑如何烹饪一些病态文字.一个简单的`\ 0`会做,+ 1. (2认同)
  • 如果您的示例使用了 `const char *abcdef = "abcdef";` 等,那么优化是合法的,但是代码将被允许比较 `def` 和 `def0gh` 的地址,并且标准指定它们将是可观察到的不同的。 (2认同)

Bat*_*eba 5

不,C++标准没有这样的保证.

也就是说,如果代码在同一个翻译单元中,那么很难找到一个反例.如果main()是不同的翻译,那么反例可能更容易产生.

如果地图位于不同的动态链接库或共享对象中,那么几乎肯定不是这种情况.

volatile限定符是一个红色的鲱鱼.