Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default constructors, initialization of POD and implicit type conversions in C++11

Tags:

c++

c++11

I have just watched Chandler's presentation on Clang at Going Native 2012. He presents the following 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);
}

Chandler states that this calls f(void*) for c++11 and f(X) for c++03. He also states that the reason is that S().n is default initialised to 0, making it a nullptr constant.

Firstly am I right in assuming that the zero initialization of member variable n is compiler implementation dependent and NOT guaranteed by the standard (or did this change with c++11)? Chandler hints this is due to support for constant expressions but I still cannot fully follow his reasoning.

Secondly why would f(X) be called with C++03 and not c++11? I would of assumed that f(void*) would kick in regardless of the value of S().n over an implicit conversion to X

For Chandler's explanation see the following link, 45 minutes in:

Clang: Defending C++ from Murphy's Million Monkeys

like image 670
mark Avatar asked Dec 09 '22 02:12

mark


2 Answers

Firstly am I right in assuming that the zero initialization of member variable n is compiler implementation dependent and NOT guaranteed by the standard (or did this change with c++11)?

No, S() means value initialize in both C++03 and C++11. Though I believe the wording for this is much clearer in C++11 than C++03. In this case, value-initialization forwards to zero-initialization. Contrast this with default-initialization which does not zero:

S s1;  // default initialization
std::cout << s1.n << '\n';  // prints garbage, crank up optimizer to show
S s2 = S();  // value initialization
std::cout << s2.n << '\n';  // prints 0

Secondly why would f(X) be called with C++03 and not c++11? I would of assumed that f(void*) would kick in regardless of the value of S().n over an implicit conversion to X

In C++03 an int can never become a null pointer constant. Once 0 is typed as an int, say by assigning it to an int, then it is forever an int, and not a null pointer constant.

In C++11, S().n is implicitly a constexpr expression with value 0, and a constexpr expression with value 0 can be a null pointer constant.

Finally, this is not an intentional change on the part of the committee as far as I can tell. If you're writing code that depends on this difference, you may well get bitten in the future if/when the committee corrects itself. I would steer well clear of this area. Use it to win bar bets -- not in production code.

like image 191
Howard Hinnant Avatar answered Mar 23 '23 00:03

Howard Hinnant


First, some clarification on the rules of initialization for both C++03 and C++11:

// This is default construction
S s;
// s.i has undefined value

// This is initialization from a value-initialized S (C++03 rules)
S s = S();
// s.i has been zero-initialized

// This is value initialization (C++11 rules)
// new syntax, better rules, same result
S s {};
// s.i has been zero-initialized

Then, remember that int is not convertible to void* so in C++03 f(S().n) will never call void f(void*); even if no other declaration of f is available.

What is possible in C++03 is to do f(0), which will call void f(void*); even if void f(X); is present. The reason for this is that the int -> X conversion (a so called user-defined conversion) is not preferred to the zero integral constant -> void* conversion (which isn't a UD conversion). Note that it's also possible to call void f(void*); via f( (int()) ) because int() is also a zero integral constant, even in C++03. (As usual the brackets are here to resolve a syntactical ambiguity.)

What C++11 changes is that now S().n is a zero integral constant. The reason for this is that S() is now a constant expression (thanks to generalized constant expression), and this kind of member access also is.

like image 36
Luc Danton Avatar answered Mar 22 '23 22:03

Luc Danton