条目三《确保容器中的副本对象高效而正确》
前两天看的《海王》,真的真的非常好看,全程无尿点。
在STL中,底层操作的都是容器存储的对象的副本。也即,对于STL而言,进去和出来都是一个对象副本。而且在STL的所有操作也只是对存储对象的副本的移动,删除等。
有副本的复制行为,证明必定有拷贝构造函数和赋值操作符重载函数的存在。如果我们没有显示的声明定义,编译器会为我们各自默认的拷贝构造函数和赋值操作符重载函数。
注意点1:
但是由于STL的操作只是对副本的操作,因此编译器默认生成的只是浅拷贝和浅赋值(赋值,其实没有所谓的深浅,因为赋值的目的本来就是单纯的复制一份源对象)。
需要特别注意的是拷贝构造函数。对于一个源对象的拷贝可分为浅拷贝和深拷贝。浅拷贝单纯拷贝值类型的值,不会对指针指向的内存拷贝。如果需要,我们必须自己实现拷贝构造函数。
好了,在这里,深浅拷贝构造函数不是重点。还是看看如何正确而高效的使用STL的容器操作,毕竟STL的操作都是副本操作。涉及到副本操作,操作不当,就会造成大量的耗时副本复制行为,造成系统效率低下。
注意点2:
< 创建了一个存放基类对象的容器,向其中插入派生类的对象,那么在派生类对象(通过基类的复制构造函数)被复制进容器时,它所特有的部分(即派生类中的信息)将会丢失。
简单来说,向基类容器插入子类对象,子类对象的特有属性会丢失。
为了容器高效,存储的应该是对象的指针而不是对象。毕竟在,在32位架构中,指针固定是4个细节,64位架构也才8个字节。然而,对于对象而言,即使只有最基本的默认构造函数,析构函数,拷贝构造函数等,已经不止8个字节了。
所以为了高效,在使用STL容器时,鼓励是存储指针而不是对象。因为,在存储的对象越来越多时,大量的对象复制行为的耗时是可观的。并且指针没有深浅拷贝的区别,也没有剥离问题发生。
注意点3:
但是,在存储指针的时候,也有烦恼的事情,一个容易想到的问题是,容器存储的指针的管理问题,如果在使用时已释放就会造成coredump。所以一个好的建议是使用智能指针。
看起来,STL容器一直在复制和操作副本,相比数组有什么优势?最简单的是自动扩容,当插入数据时内存不够会自动申请新的内存块并做数据搬移工作。达到有多少米吃多少饭的目的,绝不会也不能浪费不必要的内存。这是一大进步啊!