c++ - header 中的 `const` 和 `constexpr` 变量是否应为 `inline` 以防止违反 ODR?

标签 c++ c++17 language-lawyer one-definition-rule

考虑以下 header 并假设它在多个 TU 中使用:

static int x = 0;

struct A {
    A() {
        ++x;
        printf("%d\n", x);
    }
};

作为 this question解释说,这是违反 ODR 的,因此是 UB。

现在,there is no ODR violation如果我们的 inline 函数引用了一个非 volatile const 对象并且我们不在该函数中使用它(加上其他规定) ,所以这在标题中仍然可以正常工作:

constexpr int x = 1;

struct A {
    A() {
        printf("%d\n", x);
    }
};

但如果我们碰巧使用它,我们又回到了与 UB 的第一方:

constexpr int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};

因此,鉴于我们现在有 inline 变量,不应该将所有 namespace 范围的变量标记为 inline 在标题中避免所有问题?

constexpr inline int x = 1;

struct A {
    A() {
        printf("%p\n", &x);
    }
};

这似乎也更容易教,因为我们可以简单地说“inline-headers 中的所有内容”(即函数和变量定义),以及“从不 static 在标题中”。

这个推理正确吗?如果是,总是将 header 中的 constconstexpr 变量标记为 inline 有什么缺点吗?

最佳答案

正如您所指出的,示例一和示例三确实违反了 [basic.def.odr]/12.2.1 中的 ODR。

[..] in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization, except that a name can refer to

a non-volatile const object with internal or no linkage if the object

  • is not odr-used in any definition of D, [..]

这个推理正确吗?

是的,具有外部链接的内联变量保证引用相同的实体,即使它们被odr-used,只要所有定义都相同:

[dcl.inline]/6

An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case ([basic.def.odr]). [..] An inline function or variable with external linkage shall have the same address in all translation units.

最后一个例子是可以的,因为它满足并且不违反上面的粗体部分。

总是将 header 中的 const 和 constexpr 变量标记为内联有什么缺点吗?

我想不出来,因为如果我们 promise 通过 TU 对具有外部链接的内联变量进行完全相同的定义,编译器可以自由选择其中的任何一个来引用该变量,这将从技术上讲,与只有一个 TU 并在 header 中声明一个带有适当 header 保护的全局变量相同

关于c++ - header 中的 `const` 和 `constexpr` 变量是否应为 `inline` 以防止违反 ODR?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53794625/

相关文章:

c# - DLL中的单例被销毁

c++ - 在 C++ 中重新定义 C 函数

c++ - 为什么我的函数无限循环

c++ - GCM 中的 Crypto++ AES 正在生成类似的密文

c# - 包含语句 : c++

com - 通过使用具有有限可变参数的模板函数来限制允许的 COM 接口(interface) (std::is_same)

c++ - header 中的 const 内联 std::map 导致退出时堆损坏

c - char * 和 void * 的对象表示

c++ - 混合内联和构造函数初始化的初始化顺序

c++ - 在标准中使用 8.5.3p4,如何确定 T 与 T& 的引用兼容?