📜 ⬆️ ⬇️

Here be dragons

Looking through the materials of the GoingNative 2012 conference (which I strongly advise all C ++ programmers to look at), I noticed one example of code:

#include <iostream> struct S { int n; }; struct X { X(int) {} }; void f(void*) { std::cerr << "Pointer!\n"; } void f(X) { std::cerr << "X! \n"; } int main() { f(S().n); } 

Can you, without looking back, say what this program prints and most importantly, why ?

Under the cut, Google’s Clang developer’s suggestion about why this code works the way it works. Once again, who did not catch it: the developer of the C ++ compiler from Google does not know this for sure, it just has a guess.

Answer


When compiling in accordance with standard C ++ 98, this code will print " X! ", When compiled in accordance with standard C ++ 11, this code will print " Pointer! ".

 # clang++ -std=c++98 -g -o cxx11-4 cxx11-4.cpp # ./cxx11-4 X! # clang++ -std=c++11 -g -o cxx11-4 cxx11-4.cpp # ./cxx11-4 Pointer! 

')

Question to the developers of the standard C ++ 11




Explanations


Let's look carefully at the line

 f(S().n); 

As you can see, a copy of the S structure is created here. It does not have an explicit constructor, which means that the default constructor is called. And here comes the C ++ 11 standard with its advanced support for constant expressions ( Generalized constant expressions ). Any function (including a constructor) in C ++ 11 can be declared as always returning the same expression. This is done to enable the writing of such code:

 int get_five() {return 5;} int some_value[get_five() + 7]; 

Constant expressions are used in array declarations, in enums, in switch \ case blocks. And the C ++ 11 compiler tries any function that can be constant, to consider it exactly constant, in order to be able to use it in all these places. And what about the constructor of the structure S ? Well, if he assigns a certain number to a variable n (and the standard does not prohibit this), then it can also be a constant expression. And why would he assign n different values ​​each time? Assigns zero. Why exactly zero? Do you have any smarter meaning on your mind?
So, the above line is equivalent to:

 f(0); 

Well, as we know, this is completely equivalent:

 f(NULL); 

This is converted to void * rather than to struct X (even with the appropriate constructor X (int) ). And here we have an explicit call void f (void *) ! Well printed " Pointer! ".

Why is this not happening in a compiler with C ++ 98 support? Yes, because he does not have this very advanced support for constant expressions. The default constructor of the structure S has no reason to set the n property to zero (the standard does not require this). Well, he does not. So the string f (S (). N); cannot be uniquely converted to f (0); with all the ensuing consequences.

Conclusion


Standard C ++ 11 is new, its support in compilers is also still raw. Be prepared for similar surprises.

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


All Articles