几个例子探讨区别
C++中初始化方式有很多种,下面用几个例子来对比其区别。
- 以下3种初始化方式合法吗?
int x = 1.0;
int x(1.0);
int z{1.0};
答案:x和y的初始化合法,z的初始化不合法。
原因:大括号初始化内建类型时,禁止隐式窄化类型转换。
所谓窄化类型转换,指的是类型转换可能丢失精度,比如double转为int;反之则允许。
- 下面几行声明的是对象还是函数?
// 假设已有class Widget的定义
Widget w1;
Widget w2();
Widget w3(1);
Widget w4{};
Widget w5{1};
答案:w2声明了一个函数,返回值类型为Widget,其他几种都声明了一个Widget对象。
这就是most vexing parse。对比w2与w3,w3传入一个int类型参数,调用的是Widget(int)这个构造函数;如果想要调用Widget的默认构造函数,而去掉括号中的参数,却声明了一个返回Widget的函数。
而将小括号换成大括号,w4和w5则可以避免这个问题,声明的一定是对象而非函数。
- 下面的代码分别声明了什么样的vector?
std::vector<int> v1(10,20);
std::vector<int> v2{10,20};
答案:v1长度为10,所有元素为20;v2长度为2,元素分别为10, 20。
为什么这里用小括号和大括号有如此大的区别?可以简单的理解为vector包含这样两个构造函数:
vector(int, int);
vector(std::initializer_list);
而当使用大括号初始化时,总是会优先匹配std::initializer_list类型的参数。
模板中如何选择?
在平时的代码中,我们一般可以选择其中一种作为默认,另一种只在必要时使用。
而在模板的编写中,这是一个非常头疼的问题。
例如,想要创建一个模板,能够以任意数量参数创建任意类型对象,可以这样写:
template<typename T, typename... Ts>
void doSomeWork(TS&&.. params) {
T localObject(std::forward<Ts>(params)...); // 选择采用小括号
T localObject{std::forward<Ts>(params)...); // 或选择采用大括号
}
那么,结合上面的例子,当我们这样使用时:
doSomeWork<std::vector<int>>(10, 20);
到底是创建了长度为10,每个值为20的vector对象,还是创建了长度为2,值分别为10、20的vector对象呢?
这便取决于doSomeWork内部实现中,到底使用的是小括号还是大括号。
这正是std::make_unique和std::make_shared所面临的问题,目前的实现是,内部使用的小括号。
网友评论