Rem*_*i.b 31 c++ constructor initialization
有什么区别
std::vector<int> v;
Run Code Online (Sandbox Code Playgroud)
和
std::vector<int> v = std::vector<int>();
Run Code Online (Sandbox Code Playgroud)
直觉上,我永远不会使用第二个版本,但我不确定是否有任何区别.我觉得第二行只是构建临时对象的默认构造函数,然后由移动赋值运算符移动.
我想知道第二行是否不等于
std::vector<int> v = *(new std::vector<int>());
Run Code Online (Sandbox Code Playgroud)
要么
std::vector<int> v;
Run Code Online (Sandbox Code Playgroud)
因此导致向量本身在堆上(动态分配).如果是这种情况,那么对于大多数情况,第一行可能是首选.
这些代码行有何不同?
AnT*_*AnT 40
从C++ 17开始,没有任何区别.
有一个利基用例,其中std::vector = std::vector初始化语法非常有用(尽管不是默认构造):当人们想要std::vector<int>直接在类的定义中为类的成员提供"count,value"初始化器时:
struct S {
std::vector<int> v; // Want to supply `(5, 42)` initializer here. How?
};
Run Code Online (Sandbox Code Playgroud)
类内初始化器仅支持=或{}语法,这意味着我们不能只说
struct S {
std::vector<int> v(5, 42); // Error
};
Run Code Online (Sandbox Code Playgroud)
如果我们使用
struct S {
std::vector<int> v{ 5, 42 }; // or = { 5, 42 }
};
Run Code Online (Sandbox Code Playgroud)
编译器会将其解释为值列表而不是"count,value"对,这不是我们想要的.
所以,一个正确的方法是
struct S {
std::vector<int> v = std::vector(5, 42);
};
Run Code Online (Sandbox Code Playgroud)
son*_*yao 21
第一个是默认初始化,第二个是复制初始化 ; 这里的效果是一样的,即v通过默认构造函数初始化对象std::vector.
因为std::vector<int> v = std::vector<int>();,在概念中它将构造一个临时的,std::vector然后用它来移动构造对象v(注意这里没有赋值).根据复制省略(因为C++ 17保证),它只是调用默认构造函数来v直接初始化.
在下列情况下,编译器需要省略复制和移动类对象的构造,即使复制/移动构造函数和析构函数具有可观察到的副作用.对象直接构造到存储器中,否则它们将被复制/移动到存储器中.复制/移动构造函数不需要存在或可访问,因为语言规则确保不会发生复制/移动操作,甚至在概念上:
在变量的初始化中,当初始化表达式是与变量类型相同的类类型(忽略cv-qualification)的prvalue时:
Run Code Online (Sandbox Code Playgroud)T x = T(T(f())); // only one call to default constructor of T, to initialize x
(在C++ 17之前,复制省略是一种优化.)
这是一个优化:即使它发生并且没有调用复制/移动(因为C++ 11)构造函数,它仍然必须存在并且可访问(好像根本没有发生优化),
BTW:对于这两种情况,不会std::vector通过new表达式构造具有动态存储持续时间的对象(包括潜在的临时).