标头中的const和constexpr变量是否应为inline以防止违反ODR? [英] Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations?

查看:98
本文介绍了标头中的const和constexpr变量是否应为inline以防止违反ODR?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下标头,并假定它已在多个TU中使用:

Consider the following header and assume it is used in several TUs:

static int x = 0;

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

正如此问题所解释的,这是ODR违规行为,因此也涉及到UB.

As this question explains, this is an ODR violation and, therefore, UB.

现在,如果不违反ODR, inline函数是指非volatile const对象,并且我们不能在该函数中使用odr(加上其他规定),因此在标头中仍然可以正常使用

Now, there is no ODR violation if our inline function refers to a non-volatile const object and we do not odr-use it within that function (plus the other provisions), so this still works fine in a header:

constexpr int x = 1;

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

但是,如果我们确实要使用它,我们将与UB一起回到第一个方框:

But if we do happen to odr-use it, we are back at square one with UB:

constexpr int x = 1;

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

因此,鉴于我们现在有了inline变量,指南是否应该将标头中所有namespace范围内的变量标记为inline以避免所有问题?

Thus, given we have now inline variables, should not the guideline be to mark all namespace-scoped variables as inline in headers to avoid all problems?

constexpr inline int x = 1;

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

这似乎也更容易讲授,因为我们可以简单地说"inline-标头中的所有内容"(即函数和变量定义)以及从不标头中的static".

This also seems easier to teach, because we can simply say "inline-everything in headers" (i.e. both function and variable definitions), as well as "never static in headers".

这个推理正确吗?如果是,将标头中的constconstexpr变量始终标记为inline是否有任何不利之处?

Is this reasoning correct? If yes, are there any disadvantages whatsoever of always marking const and constexpr variables in headers as inline?

推荐答案

正如您所指出的,根据

As you have pointed out, examples one and third does indeed violate ODR as per [basic.def.odr]/12.2.1

在[D]的每个定义中的

[..] ,根据[basic.lookup]查找的对应名称,应指代在D的定义中定义的实体,在重载解析之后和部分模板专门化匹配之后,引用同一实体,除了名称可以引用

[..] 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

具有内部链接或不具有链接的非易失性const对象,如果该对象

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

    D的任何定义中均未使用
  • [..]
  • is not odr-used in any definition of D, [..]

这个推理正确吗?

是的,即使所有定义都相同,具有外部链接的内联变量也可以保证引用同一实体,即使它们是 odr用过的也是如此.

Yes, inline variables with external linkage are guaranteed to refer to the same entity even when they are odr-used as long all the definitions are the same:

[dcl.inline]/6

内联函数或变量应在使用过的每个转换单元中定义,并且在每种情况下均应具有完全相同的定义([basic.def.odr]). [..] 具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址.

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.

最后一个示例是可以的,因为它满足并且没有违反上面的粗体部分.

The last example is OK because it meets and don't violate the bold part of the above.

始终将标头中的const和constexpr变量标记为内联有什么缺点吗?

我什么都没想到,因为如果我们保证通过TU的内联变量与外部链接具有完全相同的定义,那么编译器可以自由选择其中的任何一个来引用该变量,这将从技术上讲,是相同的,因为只有一个TU,并且在标头中声明了具有适当标头保护的全局变量

I can't think of any, because if we keep the promise of having the exact same definition of an inline variable with external linkage through TU's, the compiler is free to pick any of them to refer to the variable, this will be the same, technically, as having just one TU and have a global variable declared in the header with appropriate header guards

这篇关于标头中的const和constexpr变量是否应为inline以防止违反ODR?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆