1. 程式人生 > >C++中Vector的erase()操作以及與remove的區別

C++中Vector的erase()操作以及與remove的區別

部分內容轉載地址:http://blog.sina.com.cn/s/blog_6377b8e60100ino6.html

vector <int> v;

v.pushback(0);

v.pushback(1);

v.pushback(1);

v.pushback(0);

想要刪除值為1的元素

錯誤程式碼

 vector<int>::iterator itr = v.begin();
   while (itr!=v.end())
   {
    if (*v==1)
    {
          v.erase(itr);
     }
    itr++;//這裡刪除後迭代器會更新出錯
   }

分析原因::當執行veci.erase(iter)後,迭代器iter指向了哪裡?(轉自別處)

是時候關注一下erase方法的返回值了:

An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

Member type iterator is a random access iterator type that points to elements.

看到random你就要瘋掉了吧,野指標!!!!

也就是說veci.erase(iter)後,iter的狀態是不確定的,再進行++,豈有不崩潰的道理!

正確程式碼

 vector<int>::iterator itr = v.begin();
   while (itr!=v.end())
   {
    if (*v==1)
    {
          itr=v.erase(itr);
     }

else
    itr++;
   }

每一次刪除之後,後邊的元素都會向前移動。

所以當前迭代器實際已經指向下一個元素,若再+1,實際上是指向了下一個元素的下一個元素。

以下為上述程式的詳細執行過程

int main(int argc, char* argv[])
{

 vector<int> v;

 v.push_back(1);
 v.push_back(2);
 v.push_back(3);
 v.push_back(4);

 vector<int>::iterator itr = v.begin();
 vector<int>::iterator tem = v.begin();
 while(itr!=v.end())

 {
  cout<<"line1"<<*itr<<endl;
  tem=itr;
  itr++;
  cout<<"line2"<<*itr<<endl;
  v.erase(tem);
  cout<<"line3"<<*itr<<endl;
//但我在實際執行時出錯提示“vector iterator not dereferencable”,查詢原因個人認為:

                  //當呼叫erase()後itr和tem迭代器就失效了,變成了一野指標。所以要處理這種問題,關鍵是要                              // 解決呼叫erase()方法後,itr迭代器變成野指標的問題


 }
 printf("刪除後的長度為%d",v.size());
 return 0;
}

我修改後程式碼為:

#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	vector<int>::iterator itr = v.begin();
	vector<int>::iterator tem = v.begin();
	while(itr!=v.end())
	{
		cout<<"line1"<<*itr<<endl;
		tem=itr;
		itr++;
		if (itr == v.end())
		{
			break;
		}
		else
		{
			cout<<"line2"<<*itr<<endl;
			tem = v.erase(tem);//若把tem=去掉,會報錯
			itr = tem + 1;//若這句去掉,也會報錯
			if (itr == v.end())//沒有這個判斷,也會報錯
			{
				break;
			}
			cout<<"line3"<<*itr<<endl;
		}
	}
	printf("刪除後的長度為%d",v.size());
	system("pause");
	return 0;
}


執行結果:

除錯詳解:

資料

1

2

3

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

End

Last

執行第一個迴圈

tem=itr;

資料

1

2

3

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

End

Tem itr

Last

itr++;

資料

1

2

3

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

End

Tem

itr

Last

v.erase(tem);

資料

2

3

4

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

Last

End

Tem

itr

第二輪迴圈

tem=itr;

資料

2

3

4

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

Tem

Last

End

itr

itr++;

資料

2

3

4

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

Tem

Last

End

itr

v.erase(tem);

資料

2

4

4

4

未賦值

記憶體地址

B0

B4

B8

BC

C0

指標

begin

Tem

Last

End

itr

可見,erase操作之後,last指標前移,而end指標未變,被刪除的元素後邊的元素前移,last之後的元素保持不變(並未移除)。完成之後計算size是由last-begin得到的。

vector 的刪除操作還是用如下方法:

it = v.erase(it);

即:

重新Iter迭代器指定下一個元素.

是直接賦刪除元素的下一個迭代器給Iter

實現方法的程式碼如下:

  1. for(Iter = v1.begin(); Iter != v1.end(); Iter++) 
  2.   if(*Iter == 10) 
  3.   { 
  4.    Iter = v1.erase(Iter);//Iter為刪除元素的下一個元素的迭代器
  5.   //即第一次這段語句後Iter 會是20,大家可以通過debug調試出來檢視下數值
  6.   } 
  7.   if(Iter == v1.end()) //要控制迭代器不能超過整個容器
  8.   { 
  9.    break;
  10.   } 
  11. }

remove or erase?
  很多人還用到過remove,但是對於很多人不能分清楚remove和erase的區別?

STL中remove()只是將待刪除元素之後的元素移動到vector的前端,而不是刪除。若要真正移除,需要搭配使用erase()。

vector中的remove的作用是將等於value的元素放到vector的尾部,但並不減少vector的size

vector中erase的作用是刪除掉某個位置position或一段區域(begin, end)中的元素,減少其size。(轉自別處)。


相關推薦

C++Vector的erase()操作以及remove區別

部分內容轉載地址:http://blog.sina.com.cn/s/blog_6377b8e60100ino6.html vector <int> v; v.pushback(0); v.pushback(1); v.pushback(1); v.

C++抽象類以及虛/純虛、解構函式的區別介紹

一、虛擬函式 在某基類中宣告為 virtual 並在一個或多個派生類中被重新定義的成員函式,用法格式為:virtual+函式返回型別+ 函式名(引數表) {函式體};實現多型性,通過指向派生類的基類指標或引用,訪問派生類中同名覆蓋成員函式。 二、純虛擬函式 純虛擬函式是一種

C#的結構體類的區別

nbsp display 分享 pan ron none 技術分享 初始 title (一) 語法定義上的區別,定義類使用關鍵字class 定義結構使用關鍵字struct (二) 在結構體中可以聲明字段,但是聲明字段的時候是不能給初始值的. C#中的結構體與類的區

【分析】淺談C#Control的InvokeBeginInvoke在主副線程的執行順序和區別(SamWang)

info start result 初步 總結 inter blank rap 傳遞   今天無意中看到有關Invoke和BeginInvoke的一些資料,不太清楚它們之間的區別。所以花了點時間研究了下。   據msdn中介紹,它們最大的區別就是BeginInvoke屬於

JavaScript=、==、===以及!=、!==的區別聯絡

JavaScript中=、==、===以及!=、!==的區別與聯絡   在JavaScript中,“=”代表賦值操作;“==”先轉換型別再比較,“===”先判斷型別,如果不是同一型別直接為false。其中“==”和“===”都可以用在布林表示式中,但兩者有很大的區別,下面對三者進行具體介紹:

關於C# 的布林運算子 "&" "|” 其類似的條件布林運算子 "&&" "||" 區別說明。

運算子使用說明如下:  分隔符 ———————————————————————————— 分隔符 ————————————————————————————   上述兩個運算子的結果與&和 | 完全相同,但得到結果的方式有一個重要區別:其效能比較好。兩者都是檢查第一個運算元的值(表2中的var2)

C++棧結構建立操作詳細解析

什麼是棧結構 棧結構是從資料的運算來分類的,也就是說棧結構具有特殊的運算規則,即:後進先出。 我們可以把棧理解成一個大倉庫,放在倉庫門口(棧頂)的貨物會優先被取出,然後再取出裡面的貨物。 而從資料的邏輯結構來看,棧結構起始就是一種線性結構。 如果從資料的儲存結構來進一步劃分

C++】C++變數的宣告定義的區別

宣告(declaration):意味著告訴編譯器關於變數名稱、變數型別、變數大小、函式名稱、結構名稱、大小等等資訊,並且在宣告階段不會給變數分配任何的記憶體。 定義(definition):定義就是在變數聲明後,給它分配上記憶體。可以看成“定義 = 宣告 + 記憶體分配”。 例如: #includ

makefilefor的用法以及$$$的區別

$$表示$,用來shell下引用變數,而$A或者$(A)則是Makefile的變數。 下面舉例說明: rule_1: for i in 1 2 3 4 5; do echo $(i); done 上面的程式碼不會連續列印 1 2 3 4 5 但下面的程式碼會:

C#方法引數 ref out 的區別

方法中引數的型別有三種 in型引數 in型引數通過值傳遞的方式將數值傳入方法中。即我們在Java中常見的方法 ref型引數 該種類型的引數傳遞變數地址給方法(引用傳遞),傳遞前變數必須初始化。

Oracle的left joinon和where的區別以及(+)的區別

資料庫在通過連線兩張或多張表來返回記錄時,都會生成一張中間的臨時表,然後再將這張臨時表返回給使用者。       在使用left jion時,on和where條件的區別如下: 1、 on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。 2、where條件是在臨時表生成好後

c++淺復制深復制

using 析構函數 但是 ret code 深拷貝和淺拷貝 pub set 期望 在C++中經常會遇到有關類對象的淺復制與深復制的問題,也是容易出錯的地方。 查找了相關資料,有關淺復制與深復制的定義為:對類進行復制的時候按位復制,即把一個對象各數據成員的值原樣復制到目標對

C++的new/deleteoperator new/operator delete

right urn 你在 () 析構 通用 round memory ora C++中的new、operator new與placement newC++中的new/delete與operator new/operator deletenew operator/delete

jquery之empty()remove()區別

cnblogs 指定 log 區別 com expr 節點 remove 刪除 要用到移除指定元素的時候,發現empty()與remove([expr])都可以用來實現。可仔細觀察效果的話就可以發現。empty()是只移除了 指定元素中的所有子節點,拿$("p").empt

C#&和&&的區別

poi log sha 與操作 位運算 orm 第一個 pre 繼續 SiKi老師讓我們自行查一下&和&&的區別,So... 1)&和&&都可以用作邏輯與的運算符,表示邏輯與(and),當運算符兩邊的表達式的結果都為tru

C#的is和as操作符區別小結

devel 獲取 d3d 數據 bottom 技術 datagrid idv center 1. is 是驗證操作對象是不是自己希望的 運算公式:對象 is 類型 返回true:對象是指定類型 返回false:對象不是指定類型 2. as 是將對象轉換成指定類型

HashMap底層原理以及ConCurrentHashMap區別

clas put level shm segment 區別 一個 bucket link   HashMap基於hashing原理,我們通過put()和get()方法儲存和獲取對象。當我們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashc

C#DateTime的缺陷代替品DateTimeOffset

time 另一個 blog offset gpo 運行環境 fse 規範 unix時間戳 C#中的DateTime在邏輯上有個非常嚴重的缺陷: > var d = DateTime.Now; > var d2 = d.ToUniversalTime(); &g

Mybatis整理系列(01)————傳入參數方式以及#{}${}的區別

Java實體類 erb code {} param mean ctu obj result 一、在MyBatis的select、insert、update、delete這些元素中都提到了parameterType這個屬性。MyBatis現在可以使用的parameterTyp

關於C++的繼承和過載的區別

        C++中的很多特性光從概念上的話,很難做區分。或者說,概念讓人容易模糊,比如說函式過載和函式繼承。        先說過載,過載分為操作符過載和函式名過載,其中,操作符過載就是對運算操作符的原有功能進