在《STL 源碼剖析 -- 侯捷》書籍分析的 tass-sgi-stl-2.91.57-source 源碼中。
對 vector 的 erase(); 函數有疑問:
- iterator erase(iterator position) {
- if (position + 1 != end())
- {
- //把從 position+1 到 finish 之間的元素一個一個複製到從 position 指向
- //的空間,這樣,就把 position 原來指向的元素個覆蓋了
- copy(position + 1, finish, position);
- }
-
- --finish;
- destroy(finish);
- return position;
- }
//=====================================================================
//該函數把 position 指向的對象刪除
//但是,注意(2013-6-24 wkf):
//自己認爲該函數有一個漏洞,就是: 該函數沒有真正地銷燬 position 指向的對象,
//沒有執行它的析構函數。
//假設有如下的一個列表,其內存空間表示如下:
//---------------------------------------------------------
//| 1 | 2 | 3 | 4 | 5 | | |
//---------------------------------------------------------
// |
// finish
//現在,要刪除第二個元素 2 這個對象。
//所以,執行 copy 之後,把 3, 4, 5 對象往前移動,其內存空間如下:
//---------------------------------------------------------
//| 1 | 3 | 4 | 5 | 5 | | |
//---------------------------------------------------------
// |
// finish
//注意,第 5 個元素的內存空間還是原來的對象 5 這個對象。
//然後,執行 --finish; 操作,移動指針,如下:
//---------------------------------------------------------
//| 1 | 3 | 4 | 5 | 5 | | |
//---------------------------------------------------------
// |
// finish
//然後,執行 destroy(finish); 操作,執行的是第 5 個元素的析構函數,而
//我們刪除的第2個對象,並沒有執行其析構函數,只是把它在內存空間給覆蓋了。
//如果一個對象中有 動態分配 的內存空間,就不會被釋放。
//因爲,我們都習慣於在 構造函數中使用 new 來分配內存,在析構函數中使用 delete 來
//釋放內存。
//=====================================================================
如下是一個測試的的例子:
- class test
- {
- public:
- int i;
- public:
- test(int a)
- {
- i = a;
- cout << "construct i = " << i << endl;
- }
- test(const test &a)
- {
- i = a.i;
- cout << "copy construct i = " << i << endl;
- }
- ~test()
- {
- cout << "=== destruct i = " << i << endl;
- }
- };
- void show(vector<test>& num)
- {
- vector<test>::iterator index;
- index = num.begin();
- while(num.end() != index)
- {
- cout << (*index).i << " ";
- index++;
- }
- cout << endl;
- }
-
- void main()
- {
-
- vector<test> num;
- for(int i = 0; i < 6; i++)
- {
- num.push_back(test(i));
- }
-
- show(num);
- num.erase(num.begin()+1);
- show(num);
- num.erase(num.begin()+1);
- show(num);
- num.erase(num.begin()+1);
- show(num);
-
- printf("hehe.....\n");
- getchar();
- return;
- }
運行的結果如下:
construct i = 0
copy construct i = 0
=== destruct i = 0
construct i = 1
copy construct i = 0
copy construct i = 1
=== destruct i = 0
=== destruct i = 1
construct i = 2
copy construct i = 0
copy construct i = 1
copy construct i = 2
=== destruct i = 0
=== destruct i = 1
=== destruct i = 2
construct i = 3
copy construct i = 0
copy construct i = 1
copy construct i = 2
copy construct i = 3
=== destruct i = 0
=== destruct i = 1
=== destruct i = 2
=== destruct i = 3
construct i = 4
copy construct i = 0
copy construct i = 1
copy construct i = 2
copy construct i = 3
copy construct i = 4
=== destruct i = 0
=== destruct i = 1
=== destruct i = 2
=== destruct i = 3
=== destruct i = 4
construct i = 5
copy construct i = 5
=== destruct i = 5
0 1 2 3 4 5
=== destruct i = 5
0 2 3 4 5
=== destruct i = 5
0 3 4 5
=== destruct i = 5
0 4 5
hehe.....
重點是後面的輸出:
=== destruct i = 5
0 1 2 3 4 5
=== destruct i = 5
0 2 3 4 5
=== destruct i = 5
0 3 4 5
=== destruct i = 5
0 4 5
執行的析構函數並不是需要刪除的那個對象。