在分配中使用initializer_list是否最佳做法



我已经阅读了(Bjarne Stroustrup,C++编程语言,6.3.5(关于在初始化变量时使用initializer_list,这样你就不会有缩小的转换。Bjarne 建议只使用直接列表初始化:

X a1 {v};

X a2 = {v};

X a3 = v;

X a4(v(;

其中,只有第一个可以在每种情况下使用,我强烈 推荐使用。它比 选择。

为什么Bjarne只推荐第一个?

为什么不建议在赋值(而不是初始化(中执行initializer_list?或者只是暗示你应该这样做?

a1 = {v};

这是我问的一个例子?为什么不建议initializer_list分配(据我所知(,但建议将其用于初始化?通过减少事故中潜在的缩小转换似乎是有益的。

char c;
int toobig = 256;
c = 256; //no error, narrowing occurs
c = { toobig }; //narrowing conversion, error

通常建议使用初始值设定项列表,并克服称为"最烦恼的解析"的语法陷阱。

std::vector<int> v();  

在函数内部,这看起来像变量声明,但它是函数的声明v不带任何参数返回std::vector<int>

好的,所以std::vector<int> v;修复了那个参数,但在模板中,参数可能是内置类型,其中int x;未初始化xint x{};(值(将其初始化为零。

在具有 copy elision 和几个语法规则的现代C++中,没有那么多方法可以在变量声明中意外创建临时副本。

但是初始值设定项列表确实清除了一些异常情况,值得推荐。

C++ 中的重载非常敏锐,有时仍有理由使用()来调用适当的构造函数。 例如,std::vector<T>可以采用值的初始值设定项列表并创建包含该列表的数组。伟大。 它还可以接受countvalue参数,并创建"价值"的count副本数组。也很棒。

但是,如果尺寸类型与值类型(T(兼容,您仍然可以获得惊喜!

#include <iostream>
#include <vector>
template<typename T>
void dump_vector(const std::string& tag,const std::vector<T>& vec);    
int main() {
std::vector<int> v1(5,20);
std::vector<int> v2{5,20};
std::vector<std::string> v3(5,"Hi!");
std::vector<std::string> v4{5,"Hi!"};
dump_vector("v1",v1);
dump_vector("v2",v2);
dump_vector("v3",v3);
dump_vector("v4",v4);
return 0;
}
template<typename T>
void dump_vector(const std::string& tag,const std::vector<T>& vec){
std::cout<< tag << "={ ";
auto begin=vec.begin();
auto end=vec.end();
for(auto it{begin};it!=end;++it){
if(it!=begin){
std::cout<<", ";
}
std::cout<<*it;
}
std::cout << " }n";
}

预期产出:

v1={ 20, 20, 20, 20, 20 }
v2={ 5, 20 }
v3={ Hi!, Hi!, Hi!, Hi!, Hi! }
v4={ Hi!, Hi!, Hi!, Hi!, Hi! }

带有(){}的版本为std::vector<int>做了不同的事情,但在std::vector<std::string>上登陆了相同的构造函数。

这不是一个新的或独特的问题。C++在选择重载时大量使用类型,当有一堆候选时,不同的模板实例化可能会做出意想不到的选择!

我会说初始化程序列表现在是首选。但是,当存在本身接受初始值设定项列表的构造函数时,如果您不想命中它,则可能需要显式。

也值得一读 http://read:%20https://herbsutter.com/2013/05/09/gotw-1-solution/

以这个为例

#include <iostream>
struct foo
{
explicit foo(int)
{
std::cout << "[+] c'tor calledn";
}
foo(const foo&)
{
std::cout << "[+] copy c'tor calledn";
}
};
int main()
{
std::cout << "ncreating object an";
foo a = foo{1};
std::cout << "nncreating object bn";
foo b{1};
}

使用g++ main.cpp --std=c++11 -fno-elide-constructors编译

输出:

creating object a
[+] c'tor called
[+] copy c'tor called
creating object b
[+] c'tor called

首先创建一个temporary,然后通过调用复制构造函数创建a

而在第二个示例中,对象是直接创建的。

有些few cases您必须使用()语法而不是{}

请参阅Scott Meyers-Effective Modern C++(项目7('

最新更新