使用圆括号的多个类成员变量初始化
C++ 20 中对于类成员变量的初始化,增加了支持圆括号的多个类成员变量的初始化,具体的使用方式为:
#include <iostream>
using std::cout, std::endl;
struct SA
{
int m_a;
int m_b = 2;
};
struct SC
{
int m_c;
struct SA m_d;
};
int main( int argc, char * argv[] )
{
struct SA a1( 1, 3 ); // <1> 圆括号初始化,不需要显式构造函数
struct SA a2( 2 ); // <2> 可以值初始化一部分成员变量
struct SC c1( 5, { 2 } ); // <3> 支持嵌套初始化,不过里面的对象不能用圆括号,要用大括号
cout << a1.m_a << " " << a1.m_b << endl;
cout << a2.m_a << " " << a2.m_b << endl;
cout << c1.m_c << " " << c1.m_d.m_a << " " << c1.m_d.m_b << endl;
return 0;
}
传统的圆括号的初始化,其实是相当于调用构造函数进行初始化,默认的构造函数是不带参数的,或者拷贝构造函数带一个相同的类作为参数,如果类本身支持从其他类到本类的类型转换,也支持使用,这种是仅限于一个参数。其他情况,都需要显式定义带不同参数的构造函数。
而现在有了新增的圆括号的初始化方式后,可以不需要显式定义构造函数了。
编译和运行的结果为
[smlc@test code]$ g++ -std=c++20 a4.cpp
[smlc@test code]$ ./a.out
1 3
2 2
5 2 2
[smlc@test code]$ g++ -std=c++17 a4.cpp
a4.cpp: In function 'int main(int, char**)':
a4.cpp:32:22: error: no matching function for call to 'SA::SA(int, int)'
32 | struct SA a1( 1, 3 );
| ^
a4.cpp:4:8: note: candidate: 'SA::SA()'
4 | struct SA
| ^~
a4.cpp:4:8: note: candidate expects 0 arguments, 2 provided
a4.cpp:4:8: note: candidate: 'constexpr SA::SA(const SA&)'
a4.cpp:4:8: note: candidate expects 1 argument, 2 provided
a4.cpp:4:8: note: candidate: 'constexpr SA::SA(SA&&)'
a4.cpp:4:8: note: candidate expects 1 argument, 2 provided
a4.cpp:33:18: error: no matching function for call to 'SA::SA(int)'
33 | struct SA a2( 2 );
| ^
a4.cpp:4:8: note: candidate: 'SA::SA()'
4 | struct SA
| ^~
a4.cpp:4:8: note: candidate expects 0 arguments, 1 provided
a4.cpp:4:8: note: candidate: 'constexpr SA::SA(const SA&)'
a4.cpp:4:8: note: no known conversion for argument 1 from 'int' to 'const SA&'
a4.cpp:4:8: note: candidate: 'constexpr SA::SA(SA&&)'
a4.cpp:4:8: note: no known conversion for argument 1 from 'int' to 'SA&&'
a4.cpp:34:25: error: no matching function for call to 'SC::SC(int, <brace-enclosed initializer list>)'
34 | struct SC c1( 5, { 2 } );
| ^
a4.cpp:10:8: note: candidate: 'SC::SC()'
10 | struct SC
| ^~
a4.cpp:10:8: note: candidate expects 0 arguments, 2 provided
a4.cpp:10:8: note: candidate: 'constexpr SC::SC(const SC&)'
a4.cpp:10:8: note: candidate expects 1 argument, 2 provided
a4.cpp:10:8: note: candidate: 'constexpr SC::SC(SC&&)'
a4.cpp:10:8: note: candidate expects 1 argument, 2 provided
C++17 及之前的标准,不支持圆括号初始化,所以会报错,找不到对应的构造函数。
使用圆括号和大括号进行初始化的对比
圆括号和大括号都能进行初始化,但细节上有一些差异。
大括号初始化时,不允许进行缩窄转换,例如从 double 转换成 int ,而圆括号初始化支持:
struct SD
{
int m_a;
int m_b;
};
struct SD
{
int m_a;
int m_b;
};
struct SD d1 { 3.0, 3 }; // <1> Error,大括号初始化不支持double到int的缩窄转换
struct SD d2 ( 3.0, 3 ); // <2> OK,圆括号初始化支持double到int的缩窄转换
大括号初始化时,引用临时对象,会延长临时对象的生命周期,与当前对象一样长。而圆括号初始化不会延长临时对象的生命周期,可能会导致悬空引用。
struct SE
{
int m_a;
int && m_r;
};
int func();
int n = 3;
struct SE e1 { 1, func() }; // <1> OK,func()产生的临时对象的生命周期会延长
struct SE e2 ( 1, func() ); // <2> 编译通过,运行潜在问题,func()产生的临时对象提前销毁,m_r 成为悬空引用
struct SE e3 ( 1, std::move( n ) ); // <3> OK,使用 std::move() 来进行右值引用,转移所有权,
【往期回顾】