headers 中的 `const` 和 `constexpr` 变量是否应该是 `inline` 以防止 ODR 违规?
Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations?
考虑以下 header 并假设它在多个 TU 中使用:
static int x = 0;
struct A {
A() {
++x;
printf("%d\n", x);
}
};
正如 this question 所解释的,这是 ODR 违规,因此,UB。
现在, 如果我们的 inline
函数引用了一个非 volatile
const
object 而我们不 odr-use 它在那个函数中(加上其他规定),所以这在 header:
中仍然可以正常工作
constexpr int x = 1;
struct A {
A() {
printf("%d\n", x);
}
};
但如果我们碰巧 odr-use 它,我们就回到了 UB 的第一方块:
constexpr int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
因此,鉴于我们现在有 inline
个变量,准则不应该是在 header 中将所有 namespace
范围的变量标记为 inline
以避免所有有问题吗?
constexpr inline int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
这似乎也更容易教授,因为我们可以简单地说“inline
-headers 中的所有内容”(即函数和变量定义),以及 "never static
in headers" .
这个推理正确吗?如果是,总是将 header 中的 const
和 constexpr
变量标记为 inline
是否有任何缺点?
正如您所指出的,示例一和示例三确实违反了 ODR [basic.def.odr]/12.2.1
[..] 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 时也保证引用相同的实体,只要所有定义都相同即可:
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 变量标记为内联是否有任何缺点?
我想不出任何一个,因为如果我们通过 TU 信守承诺,通过 TU 对具有外部链接的内联变量进行完全相同的定义,编译器可以自由选择其中任何一个来引用该变量,从技术上讲,这与只有一个 TU 并且在 header 中声明一个全局变量并带有适当的 header 守卫
是一样的
考虑以下 header 并假设它在多个 TU 中使用:
static int x = 0;
struct A {
A() {
++x;
printf("%d\n", x);
}
};
正如 this question 所解释的,这是 ODR 违规,因此,UB。
现在,inline
函数引用了一个非 volatile
const
object 而我们不 odr-use 它在那个函数中(加上其他规定),所以这在 header:
constexpr int x = 1;
struct A {
A() {
printf("%d\n", x);
}
};
但如果我们碰巧 odr-use 它,我们就回到了 UB 的第一方块:
constexpr int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
因此,鉴于我们现在有 inline
个变量,准则不应该是在 header 中将所有 namespace
范围的变量标记为 inline
以避免所有有问题吗?
constexpr inline int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
这似乎也更容易教授,因为我们可以简单地说“inline
-headers 中的所有内容”(即函数和变量定义),以及 "never static
in headers" .
这个推理正确吗?如果是,总是将 header 中的 const
和 constexpr
变量标记为 inline
是否有任何缺点?
正如您所指出的,示例一和示例三确实违反了 ODR [basic.def.odr]/12.2.1
[..] 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 时也保证引用相同的实体,只要所有定义都相同即可:
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 变量标记为内联是否有任何缺点?
我想不出任何一个,因为如果我们通过 TU 信守承诺,通过 TU 对具有外部链接的内联变量进行完全相同的定义,编译器可以自由选择其中任何一个来引用该变量,从技术上讲,这与只有一个 TU 并且在 header 中声明一个全局变量并带有适当的 header 守卫
是一样的