标头中的字符串 -- 这是否违反了 ODR



考虑以下具有两个编译单元的程序。


// a.hpp
class A {
static const char * get() { return "foo"; }
};
void f();

// a.cpp
#include "a.hpp"
#include <iostream>
void f() {
std::cout << A::get() << std::endl;
}

// main.cpp
#include "a.hpp"
#include <iostream>
void g() {
std::cout << A::get() << std::endl;
}
int main() {
f();
g();
}

出于某种原因需要创建全局字符串常量是很常见的。以完全幼稚的方式执行此操作会导致链接器问题。通常,人们将声明放在标头中,将定义放在单个编译单元中,或者使用宏。

我的印象是,这种使用函数执行此操作的方式(如上所示)是"可以的",因为它是一个inline函数,链接器消除了生成的任何重复副本,并且使用此模式编写的程序似乎工作正常。但是,现在我对它是否真的合法表示怀疑。

函数A::get在两个不同的翻译单元中使用,但它是隐式内联的,因为它是一个类成员。

[basic.def.odr.6]中,它指出:

可以有多个定义...内联函数 外部链接 (7.1.2)...在一个程序中,每个定义 出现在不同的翻译单元中,前提是定义满足以下要求。鉴于 在多个翻译单元中定义D命名的实体,则 -D的每个定义应
由相同的标记序列组成;并且
- 在D的每个定义中,根据 3.4 查找的相应名称应指定义的实体 在D的定义范围内,或应指同一实体,在过载解决(13.3)之后和之后 部分模板专用化 (14.8.3) 的匹配,但名称可以引用非易失性 具有内部链接或无链接的 const 对象,如果该对象在D的所有定义中具有相同的文本类型, 并且对象使用常量表达式 (5.19) 初始化,并且对象未使用 ODR,并且 对象在D的所有定义中具有相同的值;在
D的每个定义中,相应的实体应具有相同的语言联系;并且
- ...(更多似乎不相关的条件)

如果D的定义满足所有这些要求, 然后程序的行为就好像有一个单一的D定义一样。如果D的定义不满足 这些要求,则行为是未定义的。

在我的示例程序中,两个定义(每个翻译单元一个)分别对应于相同的标记序列。(这就是为什么我最初认为没关系。

但是,目前尚不清楚是否满足第二个条件。因为,名称"foo"可能与两个编译单元中的同一对象不对应 - 每个编译单元中都可能是"不同"的字符串文本,不是吗?

我尝试更改程序:

static const void * get() { return static_cast<const void*>("foo"); }

以便它打印字符串文字的地址,并且我得到相同的地址,但是我不确定这是否一定会发生。

它是否属于"...应指定义中定义的实体D"?"foo"在这里被认为是A::get内定义的吗?看起来是这样,但正如我非正式地理解的那样,字符串文字最终会导致编译器发出某种全局const char[],该存在于可执行文件的特殊段中。该"实体"是否被认为在A::get范围内,还是无关紧要?

"foo"甚至被认为是"名称",还是术语"名称"仅指有效的C++"标识符",例如可用于变量或函数?一方面它说:

[basic][3.4]
名称是标识符 (2.11)、运算符函数 ID (13.5)、文本运算符 ID (13.5.8)、转换 函数 ID (12.3.2) 或模板 ID (14.2),表示实体或标签 (6.6.4、6.1)。

标识符是


[lex.name][2.11]标识符是任意长的字母和数字序列。

所以字符串文字似乎不是名称。

另一方面在第5节

[expr.prim.general][5.1.1.1]
字符串文字是一个左值;所有其他 文字是代理值。

一般来说,我认为lvalues有名字。

你的最后一个论点是无稽之谈。"foo"在语法上甚至不是一个名称,而是一个字符串字面。字符串文字是左值,一些左值有名称并不意味着字符串文字是或有名称。代码中使用的字符串文本不违反 ODR。

实际上,直到 C++11 年,它要求跨 TU 的内联函数的多个定义的字符串文字指定同一个实体,但 CWG 1823 删除了这个多余且大部分未实现的规则。

因为,名称"foo"可能与 两个编译单元 - 它可能是一个"不同"的字符串文字 在每个中,不是吗?

正确,但这无关紧要。因为 ODR 不关心特定的参数值。如果您确实设法以某种方式在两个 TU 中调用不同的函数模板专用化,那将是有问题的,但幸运的是字符串文字是无效的模板参数,因此您必须聪明。

相关内容

  • 没有找到相关文章

最新更新