Effective STL第3条:确保容器中的对象拷贝正确而高效

一、容器元素存取时带来的拷贝

  • 一个概念:当你向容器中的存取一个对象时,实际上会伴随着拷贝操作
  • 拷贝的情景:
    • 当通过insert或push_back之类的操作向容器中加入对象时,是将对象拷贝一份进容器;当你使用容器中的一个对象时,是将对象拷贝出来使用
    • 例如vector、string、deque进行元素的插入或删除时,现有元素的位置通常会移动(拷贝)(见第5、14条)
    • 如果你使用后面任何的操作:排序算法(见第31条)、next_permutation、previous_permutatiuon、remove、unique(见第32条),rotate或reverse等等——对象将会被移动(拷贝)
  • 拷贝会带来的性能瓶颈/错误:如果对象的拷贝操作很费事,那么向容器填充对象等操作将会成为程序的性能瓶颈。放入容器的对象越多,拷贝所需的内存和时间就越多。而且,如果对象的“拷贝”有特殊含义时,把元素放入容器时将不可避免地产生错误(见第8条)

二、拷贝构造函数、拷贝赋值运算符

  • 既然讲到了对象拷贝,就讲一下C++的拷贝构造函数与拷贝赋值运算符
  • 默认拷贝构造函数与默认拷贝赋值运算符:当没有显式声明时,C++会默认定义构造函数与拷贝赋值运算符。这些默认的拷贝实现是简单地按位拷贝(详细知识可以参看Effective C++的第11条和27条)
  • 例如下面是Widget类的定义:
class Widget
{
public:
	Widget(const Widget&);   //拷贝构造函数
	Widget& operator=(const Widget&);//拷贝赋值运算符
};

三、拷贝带来的“剥离”现象

  • 当有继承关系时,拷贝动作会导致剥离
  • 如果你创建了一个存放基类对象的容器,却在其中插入派生类的对象,那么在派生类对象(通过基类的拷贝构造函数)被拷贝进容器时,它所特有的部分(属于派生类的部分)将会丢失
  • “剥离”所带来的的问题:向基类对象的容器中插入派生类对象几乎总是错误的。例如调用派生类的虚函数,那么会出现(关于剥离问题可以参阅Effective C++的第22条,关于STL剥离问题的另一个例子可以参考本专栏第38条)

演示案例

  • 下面将SpecialWidget对象放进vw容器时,派生类特有部分在拷贝时会被丢弃
class Widget{};
class SpecialWidget :public Widget {};

vector<Widget> vw;
SpecialWidget sw;

vw.push_back(sw);

解决“剥离”现象带来的问题

  • 使拷贝动作高效、正确,并防止剥离问题发生的一个简单办法是使容器包含指针而不是对象。也就是说,使用Widget*的容器,而不是Widget的容器
  • 拷贝指针的速度非常快,并且总是会按你期望的方式进行(拷贝构成指针的每一位),而且当它被拷贝时不会有任何剥离现象产生。不幸的是,指针的容器也有其自身一些问题(可以参考第7、32条)。如果你想避开这些问题,同时又想避免效率、正确性和剥离问题,可以使用智能指针(见第7条)

四、STL中一个相对于数组比较高效的地方

  • 下面我们将以STL中的vector与C或C++的内置容器(即数组)作比较,得出STL比内置数组高效的一个地方(避免不必要的拷贝)

演示说明

  • 下面创建了有maxNumWidgets个Widget对象的数组,每个对象会使用默认构造函数来创建
class Widget{};

Widget w[maxNumWidgets]; //创建了有maxNumWidgets个Widget对象的数组
  • 但是,上面我们创建了这么多个对象,其中的有些对象我们不一定会使用到,如果遇到赋值或者其他需要拷贝的地方时,就会造成程序效率很低
  • 如果我们使用STL的vector来保存Widget对象(根据vector的特性我们知道,还没有加入元素时,vector是空的,其中不包含任何对象元素)
vector<Widget> vw;//默认创建包含0个Widget对象的vector
  • 另外,我们也可以创建一个空的vector,然后扩充vector的空间可以容纳maxNumWidgets个Widget对象(但是其中没有创建任何一个Widget对象)
vector<Widget> vw;
vw.reserve(maxNumWidgets);
  • 通过上面我们可以看到,STL容器很聪明,你使用多少它就创建多少,不使用时就不创建。这就是STL高效的一个地方
发布了1313 篇原创文章 · 获赞 834 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/103962361
今日推荐