Constructor

Initialization

In a programming context, learned first in CS138 about OOP. This is whenever you use the {} syntax.

As you’ll see in the slides below, this way, you don’t do a Copy Assignment Operator, but rather directly call the default Constructor when you initialize an object inside the Constructor function.

int x{10};

This can get SUPER confusing with the edge cases.

To not use your mind, just use {}.

Some resources

C++: Initializer

  • Version two is called using a MIL as I’ve learned in CS247

Types of Initialization

  • Zero Initialization
  • Value Initialization
  • Default Initialization

If no constructor is provided, the compiler will build it for you. For all class member variables not created, it will do the default initialization (allocate the memory space).

We have two types:

  1. Primitive
  2. Class

DANGER: Primitive types are NOT always set to 0. In the case of default initialization:

#include <iostream>
using namespace std;
 
class Foo {
public:
    int x;
};
 
int main() {
	Foo foo1;
	Foo foo2{};
	cout << foo1.x << endl;  // garbage value
	cout << foo2.x << endl;  // 0
}
 
  • I was doing CS247 when I realized that I was wrong about this. The primitive type has garbage value

The initialization sort of has this recursive definition.

Default Initialization

https://en.cppreference.com/w/cpp/language/default_initialization This is the initialization performed when an object is constructed with no initializer.

This simply allocates the memory space. The values will be garbage (some compilers initialize them for optimization..?).

Rule of thumb for default-initialization:

  • Built-in types (int, char, float, pointers, etc.) will be left uninitialized, resulting in indeterminate values
  • Class types will be default-initialized

Example:

class Foo {
public:
    int a;
    std::string b;
};
 
Foo foo;  // default initialization
// foo.a has indeterminate value
// foo.b is default-constructed (empty string)
Value Initialization

https://en.cppreference.com/w/cpp/language/value_initialization This is the initialization performed when an object is constructed with an empty initializer {}.

Rule of thumb for value initialization:

  • Built-in types will be initialized to zero, or null for pointers
  • Class types will be default-initialized (NOT value-initialized)

Example:

class Foo {
public:
    int a;
    std::string b;
};
 
Foo foo{}; // value initialization
// foo.a is zero
// foo.b is default-constructed (empty string)

Warning

A certain type of initialization does not mean that everything inside the class is initialized the same way.

A class might be value initialized, but member fields are default initialized unless explicitly value intialized.

Consider the example below:

class Member {
public:
    int b;
};
 
class Foo {
public:
	int a;
    Member m; // m is default initialized
};
 
Foo foo{};  // value initialized
cout << foo.a << endl; // 0
cout << foo.m.b << endl; // garbage value (default initialization of non-static int)

To fix, you can do something like

class Foo {
public:
    Member m;
	Foo(): m{} {}
};

So you guarantee m is always value initialized when Foo is constructed:

Foo foo;
cout << foo.m.b << endl; // 0
 
  • Notice that even though foo is default initialized, Member m is value initialized
Zero Initialization

https://en.cppreference.com/w/cpp/language/zero_initialization

This is confusing, I don’t quite get the difference with value initialization. Does not have a dedicated syntax in the language.

Rule of thumb for zero initialization:

  • For built-in types, zero initialization sets the variable to zero (or null for pointers).
  • For class types, zero initialization sets each non-static member to zero.

Unfortunately, there’s no specific syntax for zero-initialization. It typically occurs in specific situations, such as when a global or static variable is declared and not explicitly initialized.

Example:

class Foo {
public:
    static int a;
    int b;
};
 
int Foo::a;   // Foo::a is zero-initialized because it's a static member
Foo foo;      // foo.b has indeterminate value because it's default-initialized
 

Example

Example taken from CS138

struct A {
	A();
	T t;
};
 
A::A() : t{} {} // t is value-initialized (C++11)
 
struct B {
	T t;
};
B::B() {} // t is default-initialized
 
void main (...) {
	T i; // default initialize
	T* j = new T; // default initialize
	T k{}; // value initialize
	T* m = new T{}; // value initialize
}