C++ Object Initialization (2023)

Initialization provides an object's initial value. The object's type,scope, storage duration, and context determine whether and how it isinitialized.

Static objects

Objects with static storage duration (i.e., variables declared at namespacescope, static class members, and static local variables) and no explicitinitializer are guaranteed to be zero-initialized:

bool b; // falsechar c; // '\0'int i; // 0double d; // 0.0void *p; // nullptrvoid f(){ static int i; // 0}class T { static int i; // declaration; definition required below};int T::i; // 0

Exactly how zero initialization occurs is implementation defined, butconventionally static objects are placed in the .bss section of theexecutable image, where they occupy no space, and are zero-filled at programstart-up (by the operating system, program loader, or language run-time).

Static objects of class type with a default constructor, that are notexplicitly initialized, are default-initialized atrun-time, before first use. When, exactly, this happens depends on theobject's scope, and, in some cases, on the compiler. static locals areinitialized the first time control passes through their declaration; globalsand static members are ostensibly initialized at program start-up, beforemain(), but compilers can defer initialization until first use:

#include <string>std::string s; // default-initialized before main() or first usevoid f(){ static std::string s; // default-initialized when f() is first called}

The order of initialization for static objects defined within a translationunit is defined (they're initialized in the order they're declared), but theorder of initialization of objects defined in different translation units isundefined. Further, the objects defined in a particular translation unit maynever be initialized if none of them is ever used by the program.

Initial values for static objects can be provided with an initializer:

#include <string>// constant initializationint i = 42;// zero initialization followed by list initializationstd::string s{"foo"};class T { constexpr T(int x) : x{x} {} int x;};// candidate for constant initializationT w = 42;

Compilers may be able to use constant initialization to construct theobject at compile-time and emit its representation in the initialized .datasection of the program image. That's the case for objects of built-in type andclass types with constexpr constructors and constant constructor arguments.

For objects of class type without constexpr constructors, the classconstructor is called at run-time, before first use, as described above fordefault initialization. This dynamic initialization stage occurs after thestatic zero initialization stage, which zero-fills the object's store atprogram start-up, before its constructor is invoked.

Automatic objects

Objects with automatic storage duration (i.e., local variables) areinitialized each time control reaches their declaration:

#include <string>void f(){ int i = 42; // initialized each time f() is called while (i--) { std::string s{"foo"}; // initialized each iteration }}

Without an explicit initializer, automatic objects are default-initialized.Objects of class type with a default constructor are default-initialized bycalling the default constructor. Objects of class type without a defaultconstructor and objects of built-in type are left uninitialized bydefault initialization. Their value is not defined; compilers should emitwarnings if such variables are used uninitialized. According to Stroustrup(TC++PL):

The only really good case for an uninitialized variable is a large inputbuffer.

Dynamic objects

Objects with dynamic storage duration (i.e., allocated with new) areinitialized by operator new after it allocates memory for the object:

int *pi = new int; // uninitializedint *pj = new int{42}; // direct-initializedT *pt = new T; // default-initializedT *pu = new T{42}; // list-initialized

As with automatic objects, dynamic objects are default-initialized ifno intializer is provided. Also like automatic objects, objects of built-intype are left uninitialized by default initialization; their values arenot defined.

Non-static members

Class constructors are responsible for initializing their non-staticmembers using an initializer list or in-class initializer:

class T { // Default constructor, default-initializes all members T() = default; // Constructor with initializer list explicit T(int x) : i{x} // direct-initialized , j{} // value-initialized {} int i = 42; // in-class initializer; overridden by initializer list int j; // uninitialized by default constructor int k; // uninitialized}

In-class initializers provide default values that can be overridden byconstructor initializer lists; if both are provided, the initializer listtakes precedence.

The generated default constructor default-initializes all non-staticmembers. As before, members of built-in type are left uninitialized bydefault initialization, and therefore will have undefined values.

Initializers

There are four syntactic styles of initialization:

  • T object{ arg1, arg2, ... };
  • T object = { arg1, arg2, ... };
  • T object(arg1, arg2, ... );
  • T object = arg;

What they mean depends on their context and the type T.

List Initialization

#include <string>#include <vector>std::string s{"foo"}; // direct list initializationstd::string t = {"foo"}; // copy list initializationstd::vector<int> v{1, 2, 3}; // direct list initializationstd::vector<int> w = {1, 2, 3}; // copy list initializationclass T { T(const std::string& s) : s{s} // direct list initialization {} std::string s; std::string t{"foo"}; // direct list initialization std::string u = {"foo"}; // copy list initialization};T* tp = new T{"foo"}; // direct list initializationT f(T t){ return {"foo"}; // copy list initialization}void g(){ f({"foo"}); // copy list initialization}

These are all forms of list initialization. The common element is thebraced-init-list, {...}. List initialization is new in C++11, and, accordingto Stroustrup, is the preferred method because it's general (available in allcontexts) and safe (immune to narrowing conversions).

The two forms of list initialization, direct and copy, differ in whether theycan call explicit constructors: direct list initialization can,copy list initialization cannot.

Generally, a list initialization of the form T t{arg1, arg2, ...} will firstsearch for a constructor taking a std::initializer_list<> as the onlynon-default argument, and failing to find a match will then search for aconstructor taking the number and type of arguments as specified in thebraced-init-list, allowing only non-narrowing conversions. Thus, after:

#include <vector>std::vector<int> v{100, 0};std::vector<int> w(100, 0);

v contains exactly two elements (100 and 0), while w contains 100elements, all 0, because std::vector<T> has both kinds of constructor:

template<typename T>class vector { vector(std::initializer_list<T> init); explicit vector(size_type count, const T& value = T());}

List initialization reduces to value, aggregate, direct, orcopy initialization in certain cases:

  • an empty braced-init-list denotes value initialization, which producesthe default value for the type
  • a braced-init-list applied to an aggregate type denotesaggregate initialization, which initializes individual members of theaggregate
  • a braced-init-list applied to a specialization of thestd::initializer_list template denotes direct or copy initialization ofthat std::initializer_list object

Value Initialization

#include <string>bool b{}; // falsechar c{}; // '\0'int i{}; // 0double d{}; // 0.0std::string s{}; // ""

Value initialization is, in effect, zero initialization followed bydefault initialization. Because default initialization leaves objects ofbuilt-in type uninitialized, value initialization of built-in types isequivalent to zero initialization:

void f(){ int i{}; // 0 int j; // undefined}

Aggregate Initialization

struct T { int x; int y; int z;};T t{1, 2, 3}; // { 1, 2, 3 }T u = {1, 2, 3}; // { 1, 2, 3 }T v{1}; // { 1, 0, 0 }char a[] = {'f', 'o', 'o', '\0'};char b[] = "foo"; // equivalentchar c[10] = {}; // zero-filled

Aggregates are arrays and simple class types (typically structs andunions) with no bases, no private members, and no user-providedconstructors. The individual elements/members of the aggregate areinitialized, in order, from the elements in the braced-init-list. If notspecified, the array size is determined by the length of the initializer. Ifthe initializer contains fewer elements than the type requires, the remainingelements are zero-initialized. As a special case, character arrays can beaggregate-initialized from string literals.

Proving that C++ is not a superset of C, C++ does not allow designatedinitializers (until C++20, at least), which C has had since C99:

struct T { int x; int y; int z;};T t = { .x = 1, // oops! can't do this in C++ .y = 2, .z = 3,};

Direct Initialization

#include <string>#include <vector>int i(42);int j{42}; // special case for braced-init-list with built-in typesstd::string s("foo");std::string t(10, 'a'); // "aaaaaaaaaa"std::vector<int> v(10); // 10 0sstd::vector<int> v(10, 5); // 10 42s

Direct intialization searches for a compatible constructor, consideringexplicit and non-explicit constructors, and performing user-defined orstandard conversions, as necessary.

Direct initialization is susceptible to the most vexing parse:

T f(); // function declaration, not (empty) direct initialization

Copy Initialization

#include <string>int i = 42;std::string s = "foo";std::string f(std::string s) // s is copy-initialized from argument{ return s + "foo";}void g(){ std::string s = "foo"; std::string t = f(s); // t is copy-initialized from temporary}

Copy initialization is less permissive than direct initialization: it onlysearches non-explicit constructors, and requires that the initializer beconvertible to the object type.

Top Articles
Latest Posts
Article information

Author: Mrs. Angelic Larkin

Last Updated: 03/20/2023

Views: 6511

Rating: 4.7 / 5 (47 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Mrs. Angelic Larkin

Birthday: 1992-06-28

Address: Apt. 413 8275 Mueller Overpass, South Magnolia, IA 99527-6023

Phone: +6824704719725

Job: District Real-Estate Facilitator

Hobby: Letterboxing, Vacation, Poi, Homebrewing, Mountain biking, Slacklining, Cabaret

Introduction: My name is Mrs. Angelic Larkin, I am a cute, charming, funny, determined, inexpensive, joyous, cheerful person who loves writing and wants to share my knowledge and understanding with you.