Vector::erase() 解析

erase()删除一个元素时,到底发生了什么

Posted by Chen on August 7, 2019

“一个人行走的范围,就是他的世界 ”

vector 是c++程序员最常用的容器,但是最近在用vector的erase()函数时,产生了一个疑问:

  1. erase()函数调用之后,整个容器的容量大小会不会发生改变?
  2. erase()里面到底发生了什么?

所以找到了SGI STL的实现源码,内容很简单:

1
2
3
4
5
6
7
// 清除某个位置上的元素
iterator erase(iterator __position) {
	if (__position + 1 != end())
​		copy(__position + 1, _M_finish, __position); // 全局函数--_M_finish;
​	destroy(_M_finish);
	return __position;
}

但是真正的问题来了:erase()里面为什么调用destroy()去析构最后一个元素(M_finish),而不是析构__position这个位置的元素?

上网搜索到了一篇博文(https://blog.csdn.net/evilswords/article/details/8930918)也验证了我的猜想。简单来说就是假如vector存储了如下序列:

A0~A3分别代表一个类的四个对象,那么当 erase(pos)时,会调用A3的析构函数。

看起来是个bug,但后来和同事讨论,发现这不能算是一个bug。因为在上述erase()源码中,copy()函数会逐个调用赋值函数(operator =),所以当删除A1时,A1还在,不过里面的值变成A2的值了。同理A2中的值变成了A3,所以最后空出一个A3来,必须析构掉。

简单写了一个测试程序,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
using namespace std;
class A {
public:
	A(int x) : value(x) {}
	A(const A &a) {
		value = a.value;
		cout << "拷贝构造函数" << value << endl;
	}
	A& operator=(const A& a) {
		value = a.value;
		cout << "赋值构造函数" << value << endl;
		return *this;
	}
	~A() {
		cout << "调用析构函数" << value <<endl;
	}
private:
	int value = 0;
};
int main()
{
	vector<A> vec;
	//vec.reserve(4);
	A a(1), b(2), c(3);
	vec.push_back(a);
	vec.push_back(b);
	vec.push_back(c);
	cout << "--------------------" << endl;
	vec.erase(vec.begin());
	return 0;
}

结果如下:

—— Chen