initialization occurs only when an object is first created
initialization gives an object its initial state
for a class type with constructors, initialization invokes a constructor
¶copy-initialization
T object = other;
¶aggregate-initialization
1 | struct S { |
remaining fields are zero-initialized.
aggregate type的要求粗糙地说是:
- 无用户自定义构造函数
- 无私有、保护成员
- 无虚函数
aggregate-initialization的缺点是使用者有完全的自由,但是有时候类的成员是存在一些潜在的数据依赖的(contract),比如size_t len; char* buf;
,{5, nullptr}
是不该被允许的。
¶without explicit initializer
- zero-initialized: object with static or thread storage duration (static, thread_local)
- indeterminate value: accessing the value is UB
¶constructors
¶direct-initialization
T object (arg1, arg2, ...);
:直接调用构造函数初始化T object {arg1, arg2, ...};
T (arg1, arg2, ...);
¶explicit constructors
拷贝初始化不考虑explicit的构造函数。
这也是直接初始化和拷贝初始化最关键的不同,拷贝初始化需要考虑类型转换问题,它会构造一个隐式的类型转换链。
¶default initialization
类会调用默认构造函数。
¶value initialization
T();
T{};
T object {};
注意T object()
被视作一个函数声明。
before C++03 缺点:
- scalar, aggregate, class type do not have uniform initialization syntax
- potential narrow conversion (
short s = i;
) - value initialization is difficult (
the most vexing parse
) - intialize STL containers is difficult
- the above issues make template type initialization difficult
Modern C++ adopts brace initialization!
¶uniform initialization syntax
all types can be initialized via braces {}
,并且它直接阻止缩窄转换。
empty braces conduct value-initialization
¶direct-list-initialization
类似于使用圆括号的direct-initialization,这里使用大括号
¶copy-list-initialization
使用大括号的copy-initialization
¶initializer list
初始化列表通常按值传递,因为它采用浅拷贝语义,可以视作视图。
STL容器都包含了初始化列表为参数的构造函数。并且初始化列表的优先级是很高的,能解释成初始化列表,就会解释成初始化列表。
如果提供了初始化列表的构造函数,要特别注意其它带有多个相同类型的构造函数。
1 | std::vector<int> v(12); // with size 12 |
1 | std::make_unique<std::vector<int>>(1, 2); |
¶总结
direct-initialization, copy-initialization, brace-initialization
- scalar type使用copy-initialization,因为这符合习惯 (most readable),而且编译器会帮你优化
- aggregate and class type尽量使用brace-initialization (direct-list-initialization),更安全并避免不必要的拷贝与隐式转换,但有时为了区别与初始化列表必须选择圆括号,注意区分
zero-initialization, value-initialization, default-initialization