Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations?

Tags:

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

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

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

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);     } }; 

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);     } }; 

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);     } }; 

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".

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

like image 203
Acorn Avatar asked Dec 15 '18 15:12

Acorn


People also ask

Is Constexpr variable inline?

A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.

Are Constexpr variables Const?

A constexpr variable must be initialized at compile time. All constexpr variables are const . A variable can be declared with constexpr , when it has a literal type and is initialized. If the initialization is performed by a constructor, the constructor must be declared as constexpr .

Should I use constexpr or inline for my constants?

In other words, you should use constexprfor your constants in header files, if possible, otherwise const. And if you require the address of that constant to be the same everywhere mark it as inline.

Is there any problem in having a constexpr variable in header file?

Is there any problem in having this in a header file that would be included to several cpp files? No A constexprvariable (int, double, etc) in do not occupy memory, thus it does not have memory address and compiler handles it like #define, it replaces variables with value.

Should constants be inline or const in header files?

In other words, you should use constexprfor your constants in header files, if possible, otherwise const. And if you require the address of that constant to be the same everywhere mark it as inline. Share Improve this answer

What is the difference between constexpr and constexpr constructors?

A constexpr constructor is implicitly inline. They serve different purposes. constexpr is mainly for optimization while const is for practically const objects like the value of Pi. Both of them can be applied to member methods. Member methods are made const to make sure that there are no accidental changes in the method.


1 Answers

As you have pointed out, examples one and third does indeed violate ODR as per [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, [..]

Is this reasoning correct?

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

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.

are there any disadvantages whatsoever of always marking const and constexpr variables in headers as inline?

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

like image 138
Jans Avatar answered Nov 11 '22 16:11

Jans