2

So I am trying real hard to understand the rules of initialization in C++.

I wrote the following code:

struct B {
  int i;

  // this prevents the definition of an implicit default constructor
  B( int j ) : i(j) {}

};

struct C {
  int i;

  // i is not mentioned in the initializer list
  // the compiler will call default constructor for i
  C() {}

};


int main() {

  int x( 1 );
  cout << " x = " << x << endl;

  // error: no matching function for call to ‘B::B()’
  //B b4 = B();
  //cout << " b4.i = " << b4.i << endl;

  C c1;
  cout << " c1.i = " << c1.i << endl;
}

1) x is correctly initialized to 1, but I don't understand the notation "int x(1)". It's not value-initialized (we would write "int x = int()", and then x would be 0). It's not a constructor call either, because built-in types do not have constructors. Besides, the following page clearly says that: "Only objects of classes with constructors can be initialized with the function-style syntax".

http://msdn.microsoft.com/en-us/library/w7wd1177(v=vs.100).aspx

2) It won't compile if I uncomment the creation of b4. Because I defined a constructor, the compiler doesn't generate an implicit default constructor. This is fine. But why does this prevent the creation of a temporary value-initialized object using "B()"? Writing "B()" is never a constructor call, is it?

3) As explained in the comments of class C, i is not mentioned in the initializer list. Therefore, it should be default-initialized, which means undefined for int type. But the output is "c1.i = 0" every time I run the program.

Thanks.

usual me
  • 8,338
  • 10
  • 52
  • 95
  • Since C++11, we typically do value initialization as `int i{};`. And there's a very quick answer to #3: Reading the value is undefined behaviour. – chris Jul 18 '13 at 02:57

3 Answers3

3
  1. int x(1); is the same as writing int x = 1; for built-in types.

  2. For a type that has a user defined constructor (non-aggregate), writing T() always calls the default constructor; that's why the code doesn't compile.

  3. c1.i is indeed uninitialized, and reading it is undefined behavior. Your compiler may be zeroing memory, especially if you don't have optimizations turned on; or it's just chance that it happens to print out zeros. You certainly cannot count on this behavior. Here's the output from clang printing garbage.

Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • If there is no user-defined constructor, `T()` if well-formed will still call the default constructor, which would have to be implicitly-defined. – Potatoswatter Jul 18 '13 at 03:13
  • 1
    "Writing `T()` *always* calls the default constructor"... except when the most-vexing parse gets involved, then it declares the type of a parameter. – Ben Voigt Jul 18 '13 at 06:07
2
  1. The notation int x(1); is called direct-initialization. It's defined separately for native types and for classes. In the latter case a constructor would be called.

  2. In this case, there is no such thing as value-initialization if there's no default constructor. The rules for constructing a temporary are the same as those for constructing a named object.

  3. Reading an uninitialized value produces undefined behavior. Running the same program again might always produce same results, but trying other programs, other machines, other platforms, may (or may not) make something else happen. Undefined literally means undefined by the standard, not crashing or random or producing an error message.

    For people who rely only on the guarantees of the best-available specs, which includes all the smart folks, a program with undefined behavior is incorrect and it can be assumed to crash when you least expect.

Community
  • 1
  • 1
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • 8.5/7: "To *value-initialize* an object of type `T` means: if `T` is a class type with a user-provided constructor [the default constructor is called]. If `T` is a non-union class type without a user-provided constructor the the object is zero-initialized and if T's implicitly-declared default constructor is non-trivial, that constructor is called. If `T` is an array type, each element is value-initialized. Otherwise, the object is zero-initialized." – Casey Jul 18 '13 at 03:55
  • @Casey Thanks, this should probably be a reply under Praetorian's answer. English translation: If there's no explicit default constructor, one may be defined implicitly. If none is defined at all, then value-initialization cannot be done. If one is implicitly-defined *but it does nothing*, then the object is zero-initialized. – Potatoswatter Jul 18 '13 at 05:28
  • It's in reply to your point 2: "There is no such thing as value-initialization if there's no default constructor," which the standard quote shows is patently false. Value-initialization is defined for both arrays (which *can't* have a constructor) and objects without default constructors (e.g., `double` and `foobar*`). – Casey Jul 18 '13 at 05:56
  • @Casey I was speaking in the context of OP's example. He cannot value-initialize an object of a particular class type because there it has no default constructor. (He seemed to expect that value-initialization *would* produce a temporary.) – Potatoswatter Jul 18 '13 at 06:00
  • Aha! At last the cognitive dissonance comes out: I see we're talking cross-purposes. Point is clearer in the edit. – Casey Jul 18 '13 at 06:02
0

If you run the program in Debug mode, it shows:

c1.i = -858993460

which is the value of "CCCCC...CC", this is the default value of uninitialized value in C++ debug mode.

athos
  • 6,120
  • 5
  • 51
  • 95