脚本宝典收集整理的这篇文章主要介绍了慎用容器的 List Initializing,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
C++11 中引进了一种叫 List InITializing 的技术,C++ PRimer 5th 的 3.3.1. Defining and Initializing vectors 中非常肤浅的介绍了一下它的形式:
vector<string> articles = {"a", "an", "the"}; // or
vector<string> articles{"a", "an", "the"};
书中颇为推崇这样的初始化方式,且形式上更加贴近 C 语言中 array 的初始化过程,很是亲民。
但我们简单做个实验,来说明这种形式在效率上可能存在的问题:
#include <iostream>
#include <vector>
struct X {
X() { std::cout << "X()" << std::endl; }
X(const X&) { std::cout << "X(const X&)" << std::endl; } // copy constructor
~X() { std::cout << "~X()" << std::endl; }
}
int main()
{
X x;
std::vector<X> vec{x, x};
}
猜猜看,这段程序的输出是什么?
X()
X(const X&)
X(const X&)
X(const X&)
X(const X&)
~X()
~X()
~X()
~X()
~X()
看看有没有猜对呢?
有没有人好奇,为什么 copy constructor 被调用了四次? 我们希望它被调用多少次呢?很显然,是两次。
我们对 main 函数稍作修改:
int main()
{
X x;
std::vector<X> vec;
vec.reserve(2);
vec.push_back(x);
vec.push_back(x);
}
然后查看本次输出:
X()
X(const X&)
X(const X&)
~X()
~X()
~X()
的确变成了我们希望的两次。如果有兴趣的话,可以将 reserve
那句话给注释掉试试,会发现调用次数变成了3次,但那不属于咱们本次探讨的范畴,如果有疑问可以留言讨论。
第二次虽然多写了几行,但貌似极大程度上的避免了 copy constructor 的频繁调用,想象一下若初始化列表里躺着一大堆 x 会有什么下场。
揭秘
copy constructor 的调用次数为何会翻倍?
因为 List Initializing 本质上是先基于列表中的元素,构造出一个 initializer_list
, 这个类型也是 c++11 引入的,可以看看详细定义。
然后,再将构造出来的 initializer_list
中的元素逐一 copy 至容器中。
故:
std::vector<X> vec{x, x};
相当于:
std::initializer_list<X> list = {x, x}; // copy 2 times
std::vector<X> vec(list); // copy 2 times
真相大白。
结论
对于非 built-in 对象来说, 使用 List Initializing 付出的代价,在某些情况下不容忽视。
过去陈旧的写法,反而让人更加踏实。
以上是脚本宝典为你收集整理的慎用容器的 List Initializing全部内容,希望文章能够帮你解决慎用容器的 List Initializing所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。