初始化表达式的每种方式的优缺点是什么?

时间:2013-09-10 23:50:49

标签: c++ c++11 c++14

这是受到Andrei Alexandrescu的post的启发。

使用以下方法初始化表达式的专家和概念是什么?我什么时候应该更喜欢一个?

auto v = expr;
T v = expr;
auto v(expr);
T v(expr);
auto v { expr }; 
T v {expr};

5 个答案:

答案 0 :(得分:15)

auto v = expr;
auto v(expr);

在您的代码中,您不知道expr的类型并希望保持通用,或者在您的代码中,绝对清楚expr的类型(在上面的行中定义)等等),auto不会增加混淆。

初始化的形式,parens与否,是无关紧要的(仅与语言律师有关,因为存在微妙的差异)。使用你感觉更舒服的东西。


T v = expr;
T v(expr);

如果您的代码中不清楚expr是什么(定义太远,等等......),或者您不知道expr的类型但想要{{1} }属于v类型。如果你想继续使用“expr”所具有的“种类值”(即T是字符串而expr是字符串类型),请使用第一种形式。如果您构建了一种全新的值(即T,并且Widget是窗口小部件的颜色),请使用第二种形式。


expr

永远不要在当前的C ++中使用它(可能在未来几年内)。它会将auto v { expr }; 声明为v。如果需要,请直接使用该类型并将其写出。它太过微妙了(并且有超出C ++ 14的提议来改变这个事实,所以希望你可以用C ++ 17或类似的东西来写这个。)


std::initializer_list<TypeOfExpr>

如果你想保护自己免受缩小转换(即意外地从T v {expr}; 转到1000),或者你想初始化一个具有初始化列表构造函数的类,或者你有一个聚合您要初始化的成员,使用此表单。或者,如果您正在处理初始化列表构造函数,聚合或简单的非类类型,则可以使用以下内容

char

使用它来调用任意构造函数。我会使用以下表格

T v = { expr };

然而,也有人喜欢使用括号形式。我想知道我的代码是做什么的,因此当我想调用一个构造函数,并且不想随意进行聚合或列表初始化构造函数调用时,我使用parens而不是braces。

答案 1 :(得分:5)

auto v = expr; T v = expr;很好,但在自动版中,可能很难理解expr的类型。

例如,在auto x = snafuscate();中,x ??

的类型是什么

如果存在歧义,最好明确声明右侧的类型为:auto x = Gadget { snafuscate() };

...

auto v(expr);T v(expr);是一个坏主意,因为有效的expr也可以理解为函数指针。

此代码无法编译:

int main()
{
    int x(int());
    return x + 3;
}

prog.cpp:4:11: error: invalid conversion from ‘int (*)(int (*)())’ to ‘int’ [-fpermissive]
return x + 3;
         ^

...

auto v { expr };几乎总是错误的,因为v的类型变为initializer_list而不是T.

查看有关自动的最佳做法:http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/

答案 2 :(得分:5)

除了含义不同的情况(例如vector<int> v(12)没有给出一个值为12的向量),编译器应该为上述所有内容提供相同的东西,它确实是只是个人偏好决定哪个是“更好”。

当类型难以键入时,

auto非常有用,并且从上下文中可以清楚地看到类型。但auto x = 12;很难判断它是签名还是未签名,例如[我不知道规则,可能签名]。

答案 3 :(得分:2)

我认为,不需要使用auto作为

auto x = 12332; // or
auto z = 0xffff; //

由于,

auto x = 12332; // type is  'int'
auto x2 = 0xffff // type is 'int'
auto y = 0xffffffff; // 8 fs,  type is unsigned int
auto z = 0xfffffffff;// 9 fs,  type is long long
auto t = 0xffffffffffffffff; // 16 fs, type is unsigned long long.

但是,你可以使用

auto size = array.size();

答案 4 :(得分:2)

这是一个非常困难的问题。

有两个不同的问题。

首先是否使用类型推导,即使用auto说明符或明确指定类型。一般来说,我会说最好明确指定类型以帮助提高可读性,除非类型很长且很麻烦(例如迭代器):

auto it = vec.begin();

或者初始化程序中的类型是否明显:

auto pfoo = new Foo(x,y,z);

或者如果您不关心可读性。

第二种是使用什么类型的初始化。有直接初始化,复制初始化和列表初始化 - 初始化的行为在很大程度上取决于目标的类型。它们之间的差异在C ++标准的8.5节中描述。初始化也出现在更多地方而不仅仅是简单的声明。初始化发生在参数传递,返回值,子表达式,语句条件,数组边界和许多其他地方。这真的是你需要了解的细节,一些简短的总结不会削减它。