Defining C ++ Static Constants

I understand that static const members must have an out-ouf class definition that they use odr. But the fact is that my program compiles and works just fine even without identifying members.

Let's look at this example from the C ++ FAQ:

class AE { public: static const int c6 = 7; static const int c7 = 31; }; const int AE::c7; // definition void f() { const int* p1 = &AE::c6; // error: c6 not an lvalue const int* p2 = &AE::c7; // ok cout << *p1 << endl; } int main() { f(); const int* p1 = &AE::c6; std::cout << p1 << "\n"; return 0; } //RESULT: // 7 // 00007FF735E7ACE8 

I do not see a mistake. I am using Visual Studio 2015 and this code compiles and works just fine.

My question is: Is this specific to msvc or are there some language changes that I don't know about?

UPDATE: This is not a duplicate, as I said at the very beginning: I understand how this should work, I do not understand why it does not work properly.

+5
source share
3 answers

The program clearly violates one rule of definition, as you stated in your question. But in this case, the standard does not require diagnostics. This is explicit from 3.2. One definition rule [basic.def.odr] Β§4 (emphasis)

Each program must contain exactly one definition of each non-line font or variable that is used as odr in this program; no diagnostics required .

and 1.4 Execution of the execution of [intro.compliance] Β§2.3 says:

If a program contains a violation of a rule for which no diagnostics are required, this International Standard does not require any implementation requirements for this program.

This means that gcc is right to strangle this program because one rule has been violated. But this is not a mistake when MSVC accepts it as a compiler extension (*) without warning, because the standard does not require any requirements here.

We are in undefined compilation time, called a poorly formed program that does not require diagnostics. A compiler implementation can do anything:

  • reject program
  • automatically fix the error and generate the code as if the definition were (for the current case)
  • remove the offensive line [s] if that makes sense and compiles the program - even if what is being generated does not match the expected programmer
  • compile it into a program that ends with a runtime error
  • [add everything you think, but I never saw the compiler hit my cat ...]

(*) more precisely, this is a compiler extension, if documented. Unfortunately, at the moment I do not have complete documentation for the MSVC compiler, so I can’t say whether it is documented and is a compatible extension or not, and this is just ... one possible program execution

Below is a small version of the OP code, demonstrating that the compiler provided a definition:

 #include <iostream> class AE { // ... public: static const int c6 = 7; static const int c7 = 31; }; const int AE::c7; // definition int main() { const int* p1 = &AE::c6; // error: c6 not an lvalue const int* p2 = &AE::c7; // ok // ... std::cout << *p1 << "(" << p1 << ") - " << *p2 << "(" << p2 << ")" << std::endl; return 0; } 

Exit (with old MSVC 2008, debug mode to avoid as much optimization as possible):

 7(00DF7800) - 31(00DF7804) 

i.e. expected values ​​and sequential addresses

With the same code, Clang 3.4 complains (as expected) about link time with

 undefined reference to `AE::c6' 
+5
source

It so happened that your compiler has applied some optimizations, which means that in this case you do not need to follow the rule of determining one line.

However, the C ++ standard still requires you to do this, so your program has undefined behavior. The standard does not require the compiler to tell you when you break this rule, so it was not chosen. In fact, this would have to make an extra effort to detect the problem.

+1
source

The C ++ standard says ([basic.def.odr] 3.2 paragraph 2) "The variable name of which is displayed as a potentially evaluated expression, odr is used if it is not an object that satisfies the requirements for appearing in constant expression (5.19) and lvalue- to-rvalue (4.1) is applied immediately.

Read this for further details.

0
source

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


All Articles