概述
作为TotW#88最初发表于2015年6月27日
由Titus Winters (titus@google.com)创作,代表Google C++风格仲裁者
C++11提供了一种称为“统一初始化语法”的新语法,它被认为统一所有不同风格的初始化,避免最烦人的解析,并避免窄化转换。这种新机制意味着我们现在有另一种初始化语法,它有自己的权衡。
C++11括号初始化
一些统一初始化语法的支持者会建议我们使用{}和直接初始化(不使用‘=’,尽管在多数情况下两种形式调用相同的构造函数)来初始化所有类型:
int x{2};
std::string foo{"Hello World"};
std::vector<int> v{1, 2, 3};
对比(例如):
int x = 2;
std::string foo = "Hello World";
std::vector<int> v = {1, 2, 3};
这种方法有两个特点。首先,“统一”是一个延伸概念:在某些情况下,在调用什么以及如何调用这方面依然存在歧义(针于普通读者,而不是编译器)。
std::vector<std::string> strings{2}; // 两个空字符串的vector
std::vector<int> ints{2}; // 仅仅一个整数2的vector
其次:这种语法并不完全直观:没有其他通用语法像这样使用。这种语言当然可以引入新的令人惊讶的语法,并且在某些情况下有必要使用它的技术原因——尤其是在通用代码中。重要的问题是:我们应该在多大程度上改变我们的习惯和语言理解来利用这种改变?改变我们的习惯或存在的代码,这种代价是否值得?对于统一初始化语法,我们一般不认为利大于弊。
关于初始化的最佳实践
相反,我们推荐下面的指南来进行”如何初始化一个变量?”,既可以在你自己的代码中遵循,也可以你的代码审查中引用:
- 当用预期的字面量(例如:int,float或std::string值)、智能指针(例如std::shared_ptr,std::unqie_ptr)、容器(std::vector,std::map等)来直接初始时,当执行结构体初始化或进行深拷贝时,请使用赋值语法。
int x = 2;
std::string foo = "Hello World";
std::vector<int> v = {1, 2, 3};
std::unique_ptr<Matrix> matrix = NewMatrix(rows, cols);
MyStruct x = {true, 5.0};
MyProto copied_proto = original_proto;
而不是:
// 糟糕的代码
int x{2};
std::string foo{"Hello World"};
std::vector<int> v{1, 2, 3};
std::unique_ptr<Matrix> matrix{NewMatrix(rows, cols)};
MyStruct x{true, 5.0};
MyProto copied_proto{original_proto};
- 当初始化正在执行一些活动的逻辑时,使用传统的构造函数语法(用括号),而不是简单地将值组合在一起。
Frobber frobber(size, &bazzer_to_duplicate);
std::vector<double> fifty_pies(50, 3.14);
对比
// 糟糕的代码
// 可以调用一个初始化列表构造函数,或者一个两个参数的构造函数
Frobber frobber{size, &bazzer_to_duplicate};
// 制作一个2个double的vector
std::vector<double> fifty_pies{50, 3.14};
- 只有以上选项不能编译时,才使用{}初始化而不用=
class Foo {
public:
Foo(int a, int b, int c) : array_{a, b, c} {}
private:
int array_[5];
// 因为构造函数标记为explicit并且是非拷贝类型,因此需要{}
EventManager em{EventManager::Options()};
};
- 绝不滥用{}和auto
例如,不要这样做:
// 糟糕的代码
auto x{1};
auto y = {2}; // 这是std::initializer_list<int>!
(对于语言律师而言:如果可行,优先使用拷贝初始化而不是直接初始化,并在直接初始化时使用圆括号而不是大括号。)
也许对这个问题最完整的描述是Herb Sutter的GotW贴文。尽管他展示了一个直接用大括号初始化int的示例,但是他最终的建议大致与我们在此提出的建议相符:Herb说“在那里你更愿意只看到=符号”,我们毫不含糊地优先确定地看到那个。结合更加一致地在多参数构造函数上使用explicit(参见贴士#142),这提供了在可读性、确切性和正确性之间的平衡。
结论
统一初始化语法的权衡结果通常是不值得的:我们的编译器已经警告了最烦人的解析(你可以使用大括号初始化或添加括号来解决这个问题),并且窄化转换的安全性不值得为可读性去使用大括号初始化(我们最终需要一个不同的解决方案来进行窄化转换)。风格仲裁者认为这个问题不足以制作一个正式的规则,特别是因为在某些情况下(尤其是在通用代码中)大括号初始化可能是合理的。
最后
以上就是害怕豆芽为你收集整理的本周小贴士#88:初始化:=,()和{}C++11括号初始化关于初始化的最佳实践结论的全部内容,希望文章能够帮你解决本周小贴士#88:初始化:=,()和{}C++11括号初始化关于初始化的最佳实践结论所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复