本文共 1337 字,大约阅读时间需要 4 分钟。
看了一下vector的实现,感觉C++的内存管理,确实是需要非常认真对待的。
为了追求效率,自身就需要仔细万分,总结了3,4点感觉尤其如此。
1.vector的底层实现
这个倒是很简单,vector就是一段动态分配内存的数组,加上冗余空间,所以用三个指针(迭代器)就能表示出来,底层的数据结构。
分别是迭代器:start、finish、end_of_storage
其中,finish-start=size,end_of_storage-start=capacity
2.vector的一系列操作
(1)增
push_back<---------->emplace_back
insert<------------------>emplace
emplace是通过填入参数,然后调用其他构造函数,构造对象
push和insert是调用拷贝构造函数构造对象
(2)删
pop_back
erase
clear
注意:只有对中间操作的函数才有返回值,且返回值为iterator。
比如,insert、emplace、erase
最最复杂的操作应该就是insert操作了。
3.copy和copy_backward
copy(first, end, result)
将从first到end的对象拷贝到,result开始的一段内存区域。
顺序为:first--》result, first+1--》result+1,。。。, first+(end-first-1)--》result+(end-first-1)
copy_backward(first, end, result)
顺序为:end-1--》result-1, end-2--》result-2, 。。。, first--》resutl-(end-first+1)
注意:由于不管是copy还是copy_backward都是一个一个移动的,所以当用copy向右移动,且移动长度小于要移动的序列长度时,有坑,会覆盖。
当copy_backward向左移动,且移动长度,小于要移动的序列长度时,有坑,会覆盖。
4.copy和uninitialized_copy
这个问题我发现了,后来到知乎上去看,别人也有同样的疑问:
简单来说,就是copy和uninitialized_copy的区别。
前者假设对象已经构造好了,后者假设是在一段申请的raw memory里面,要先construct再进行copy。
当然对于原始类型来说,不用construct,所以其实uninitialized_copy如果遇到原始类型会调用copy,如果不是就要一个一个调用construct
这么做的原因,在上面那个连接里面有解释。
简单来说,就是如果是定义的类,有可能会有动态分配内存持有指针的情况,如果没有调用构造函数,而是直接使用,
如果直接使用,那么指针未经初始化,delete一个未经初始化的指针,后果很严重。
因为未经初始化的指针,指向一个不确定的内存空间,这个内存空间可能正在被使用,存放重要信息,
这个时候你把这个内存里面的内容delete=destroy(调用析构函数)+deallocate(将内存返还给系统)
只能说,雪崩。
转载地址:http://rniei.baihongyu.com/