NOTE: Every post ends with "END OF POST". If you don't see it then open the full post in a separate page!

Variable declaration and initialization


Initialization in C++ is a complex topic!
Some of the initialization types of C++ are the followings:

  • Default Initialization: If a variable is not initialized explicitly. The value is garbage.
  • Value Initialization: Initializes with the type’s default initial value (e.g. default constructor for user types, zero for number types).
  • Direct Initialization: Initializes with the given value.

The example below shows what happens to variables when initialized with these different initialization types.

#include <iostream>
#include <cstdint> // uint64_t
#include <algorithm> // fill
using namespace std;

static uint64_t garbage[32];
template<typename T>
void print(const string& m, const T& a)
{ cout << m << ": (" << a.d << "," << a.f << "," << a.s << "," << a.i << ") "
       << endl; }
static void reset() { fill(begin(garbage), end(garbage), 0xDEADBEAF); }

class A {
public: double d;  float f;  string s; int i;
};

class B {
public: double d;  float f;  string s; int32_t i;
  B() {}
  explicit B(int8_t a) : i{a} {}
  explicit B(uint8_t a) : d{}, f{}, s{}, i{a} {}
  explicit B(int16_t a) : d{}, s{}, i{a} {}
  explicit B(double ad, float af, string as, int ai)
           : d{ad}, f{af}, s{as}, i{ai} {}
};

int main() {
  reset();

  auto v1 = new (garbage) A; // Placement New syntax.
  print("Default", *v1); reset();

  auto v2 = new (garbage) A{};
  print("Value without default ctor", *v2); reset();

  auto v4 = new (garbage) B{};
  print("Value with default ctor", *v4); reset();

  auto v5 = new (garbage) B{int8_t{2}};
  print("Direct with Default in ctor", *v5); reset();

  auto v6 = new (garbage) B{uint8_t{2}};
  print("Direct with Value in ctor", *v6); reset();

  auto v7 = new (garbage) B{int16_t{2}};
  print("Direct with Value and Default in ctor", *v7); reset();

  auto v8 = new (garbage) B{1.0, 2.0, "Moikkelis!", 3};
  print("Direct with Direct in ctor", *v8); reset();

  auto v3 = new (garbage) A{1.0, 2.0, "Hello!", 3};
  print("Aggregate", *v3); reset();

  return 0;
}

Here is the output of the above code:

Default: (1.84579e-314,-6.25982e+18,,-559038801) 
Value without default ctor: (0,0,,0) 
Value with default ctor: (1.84579e-314,-6.25982e+18,,-559038801) 
Direct with Default in ctor: (1.84579e-314,-6.25982e+18,,2) 
Direct with Value in ctor: (0,0,,2) 
Direct with Value and Default in ctor: (0,-6.25982e+18,,2) 
Direct with Direct in ctor: (1,2,Moikkelis!,3) 
Aggregate: (1,2,Hello!,3) 

The “ugly” floating point numbers represent uninitialized variables. As you can see, sometimes initialization does not happen even thou you thought it would.

Here are some tips in order to avoid common pitfalls:

  • Always initialize during declaration!
  • Prefer Direct Initialization.
  • Careful with Value Initialization of user types with user-defined default constructor: It can leave things uninitialized if the programmer accidentally left some member variables Default Initialized.
  • Avoid Default Initialization (i.e. no initialization).

References:
http://en.cppreference.com/w/cpp/language/default_initialization
http://en.cppreference.com/w/cpp/language/value_initialization
http://en.cppreference.com/w/cpp/language/direct_initialization
http://en.wikipedia.org/wiki/Placement_syntax

END OF POST



Leave a comment