Skip to content

Value initialization

1、value initialization和default initialization一样,也是不带参数的,value initialization比default initialization多做了一点: 对于non-class type,对它们执行zero initialization。

cppreference Value initialization(since C++03)

Syntax

syntax explanation
T()
T{}
a nameless temporary object is created
with the initializer consisting of an empty pair of parentheses or braces (since C++11);
new T ()
new T {}
an object with dynamic storage duration is created by a new-expression
with the initializer consisting of an empty pair of parentheses or braces (since C++11);
Class::Class(...) : member() { ... }
Class::Class(...) : member{} { ... }
a non-static data member or a base class is initialized using a member initializer
with an empty pair of parentheses or braces (since C++11);
T object {}; a named variable (automatic, static, or thread-local) is declared with the initializer consisting of a pair of braces. (since C++11)

NOTE:

1、{}是C++11引入的uniform initialization特性,参见 list-initialization

2、我没有按照原文的方式,而是将相同内容进行了合并

3、需要注意的是,对于value initialization,它是不支持 T object(); syntax的,因为compiler将它作为function declaration,参见后面的"Notes"章节

Aggregate-initialization

In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.

NOTE:

1、aggregate-initializationlist-initialization 一致

List-initialization

If T is a class type that has no default constructor but has a constructor taking std::initializer_list, list-initialization is performed.

NOTE: 如果既有default constructor,又有constructor taking std::initializer_list,那compiler如何选择呢?

Effect

NOTE: 按照在C++\Language-reference\Initialization\Initialization中总结的思路来进行整理。

Class type

NOTE: 关于class type的initialization规则是最最冗杂的,下面结合了具体的例子来进行了说明。

(until C++11)

1) if T is a class type with at least one user-provided constructor of any kind, the default constructor is called;

NOTE: 这条规则和C++11中的相同

2) if T is a non-union class type without any user-provided constructors, every non-static data member and base-class component of T is value-initialized;

NOTE: 和C++11中有什么差异呢?下面的2)中给出的例子就体现了两者的差异。

(since C++11)

1) if T is a class type

a) with no default constructor or

b) with a user-provided (default constructor) or

c) with a deleted default constructor

the object is default-initialized;

NOTE: 结合下面的具体例子来看,上述a)、c)都会导致编译报错,只有b)是能够编译通过的。这条规则其实描述的是当b)的时候,compiler只会这些user-define default constructor,而无法做任何事情,因为此时的default constructor是user-provided,compiler没有控制权,所以它不敢执行 zero-initialization

2) if T is a class type with a default constructor that is neither user-provided nor deleted
(that is, it may be a class with an implicitly-defined (default constructor) or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

NOTE: 关于2)中的最后一句,在原文的Notes章节中有专门的解释,下面将它整理到了这一段中。

Since C++11, value-initializing a class without a user-provided constructor, which has a member of a class type with a user-provided constructor, zeroes out the member before calling its constructor:

NOTE: 显然先 zero-initialization 然后再 default-initialization 是非常安全的,既能够保证zero-initialization又能够安全地执行default-initialization。

#include <string>
#include <vector>
#include <iostream>

struct A
{
    int i;
    A()
    {
    } // user-provided default ctor, does not initialize i
};

struct B
{
    A a;
};
// implicitly-defined default ctor

int main()
{
    std::cout << B().a.i << '\n'; // value-initializes a B temporary
                                  // leaves b.a.i uninitialized in C++03
                                  // sets b.a.i to zero in C++11
}
// g++ --std=c++11 test.cpp

NOTE: 输出如下:

0

NOTE: 下面例子对上面两条规则中描述的各种情况进行了说明:

default constructor example effect
with no default constructor struct T2 编译报错,因为没有default constructor,所以不允许 T2 t2{ };
compile error: class with no default constructor
with a user-provided (default constructor) struct T3 符合上述1)中的default-initialized;从输出可以看到,user-provided default constructor被调用
由于在user-provided default constructor中没有初始化mem1
所以它的value是indeterminate
with a deleted default constructor struct T5 编译报错,因为没有default constructor,所以不允许 T5 t5{ };
implicitly-defined (default constructor) struct T1 符合上述2)
defaulted default constructor struct T4 符合上述2)
#include <string>
#include <vector>
#include <iostream>

// implicit default constructor
struct T1
{
    int mem1;
    std::string mem2;
};

struct T2
{
    int mem1;
    std::string mem2;
    T2(const T2&) // user-provided copy constructor、no default constructor
    {
    }
};

struct T3
{
    int mem1;
    std::string mem2;
    T3() // user-provided default constructor
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct T4
{
    int mem1;
    std::string mem2;
    T4() = default;
};

struct T5
{
    int mem1;
    std::string mem2;
    T5() = delete;
};
int main()
{
    T1 t1 { }; // class with implicit default constructor =>
               //     t1.mem1 is zero-initialized, the value is 0
               //     t1.mem2 is default-initialized, the value is ""
//  T2 t2{ }; // error: class with no default constructor
    T3 t3 { }; // class with user-provided default constructor =>
               //     t3.mem1 is default-initialized to indeterminate value
               //     t3.mem2 is default-initialized, the value is ""
    T4 t4 { };

//  T5 t5 { }; // error: use of deleted function ‘T5::T5()’
    std::cout << t1.mem1 << ' ' << t3.mem1 << ' ' << t4.mem1 << '\n';
}
// g++ --std=c++11 test.cpp

NOTE: 输出如下:

T3::T3()
0 720930048 0

Array type

3) if T is an array type, each element of the array is value-initialized;

Other type

4) otherwise, the object is zero-initialized.

NOTE: 这是value initialization和default initialization的重要差异所在。

Notes

NOTE: 原文这一段中关于(){}的讨论,都收录到了C++\Language-reference\Initialization\Uniform-initialization.md中。

A constructor is user-provided if it is user-declared and not explicitly defaulted on its first declaration.

NOTE: “not explicitly defaulted on its first declaration”的含义是:

class C
{
public:
C()=default;
}

这是C++11引入的新特性。

Syntax ambiguity in value initialization and function declaration

NOTE:

这部分内容移到了"Syntax-ambiguity-in-initialization-with-round-parenthese"章节

Example

#include <iostream>

struct Test
{
    int a;
    int b;
};

class C
{

public:
    Test t;
};

int main()
{
    C c;
    std::cout << c.t.a << std::endl;
    std::cout << c.t.b << std::endl;
}

上述例子是不使用zero initialization,可以看到c.t.ac.t.b都是随机值。

#include <iostream>

struct Test
{
    int a;
    int b;
};

class C
{

public:
    Test t { };
};

int main()
{
    C c;
    std::cout << c.t.a << std::endl;
    std::cout << c.t.b << std::endl;
}

上述例子是使用zero initialization,可以看到c.t.ac.t.b都是默认值0。

作为对比,可以看看下面的例子:

#include <iostream>

struct Test
{
int a;
int b;
};


class C
{

public:
    Test t {1};

};

int main()
{
    C c;
    std::cout<<c.t.a<<std::endl;
    std::cout<<c.t.b<<std::endl;
}

输出如下:

1
0

作为对比,看看涉及Value initialization的例子:

// C++ code to demonstrate zero initialisation 

#include <iostream> 
#include <string> 

struct foo { 
    int x, y, z; 
}; 

double f[3]; // zero-initialized to three 0.0's 

int* p; // zero-initialized to null pointer value 

// zero-initialized to indeterminate value 
// then default-initialized to "" 
std::string s; 

int main(int argc, char* argv[]) 
{ 
    foo x = foo(); 

    std::cout << x.x << x.y << x.z << '\n'; 

    return 0; 
} 

输出为:

000