C ++: "double freedom or corruption" for a global external variable?

I am interested in having a global variable at a time throughout the program. So I thought the best way to achieve this is to define it in the header file as follows:

extern const std::string CONST_STR = "global string"; 

But this led to a "double release or damage" error. If you reset extern , the problem will disappear.

  • Can anyone explain this behavior?
  • AFAIK, without specifying extern , there will be CONST_STR for each translation unit, is there no way to get one fully global variable const?
+4
source share
2 answers

An appeal to the first part and additional questions about the loss of extern.

 const std::string CONST_STR = "global string"; 

According to C ++ rules, this is identical:

 static const std::string CONST_STR = "global string"; 

If it is in the included file, you will create different lines in each translation unit (TU). They all work fine on their own, but suppose you also added a function in one header:

 inline void foo() { std::cout << CONST_STR; } 

If the << operator accepts the string const& , then in each TU it will be bound to a separate line. Thus, the β€œone definition rule” is violated and placed in undefined (UB) behavior. In practice, this most likely works, but, nevertheless, it is UB.

The original extern form is similar to this, since the same-looking string literals are also separate in different TUs.

If you simply say extern without an initializer, this declaration will be resolved by the linker for a single definition. If you use an initializer, this makes it a definition. Thus, an object is created in each TU, but using a common public name, expecting other TUs to gain access to it. Implementation is exempt from liability as you must ensure that only one definition is actually provided.

Unfortunately, one rule of definition will break too easily, and most of its forms clearly allow the implementation to not produce any diagnostics. In practice, the linker simply selects a random definition from the pool. The double free one is probably caused by _atstart and _atexit for constructor and destructor calls, the object itself melts into one, then it receives as many constructor and destructor calls as you have TU.

For implementation, this is all fair play, since everything goes for UB.

+4
source

Put a definition

 const std::string CONST_STR = "global string"; 

exactly in one compilation unit (the usual thing to do is put it in the source file).

In the headers write only the declaration:

 extern const std::string CONST_STR; 

This ensures that you only have one version of the string in the entire program. I'm rather surprised that your linker did not complain about how you did it.

+3
source

Source: https://habr.com/ru/post/1488502/


All Articles