STL Vector 的遍歷刪除
阿新 • • 發佈:2019-01-01
Vector 其實就類似動態陣列. 事先分配好一定量的記憶體. 當需要的記憶體值大於某個閥值. 就重新申請記憶體. 重新分配. 當小於某個閥值, 也會導致重新分配.(自動收縮部分, stl沒有明確規定, 有些庫實現了)
正確: code1
vector<string> vecFiles;
vector<string>::iterator it_pos;
//@todo 已下載檔案過濾
for (it_pos = vecFiles.begin(); it_pos != vecFiles.end(); ) {
string strTmp = *it_pos;
if( objDownHis.checkHisList( strTmp.c_str() ) ){ //判斷是否已下載過, 已下載則從列表刪除
g_Log << TIME << "file:[" << *it_pos << "] found "<< END; //
vecFiles.erase(it_pos++);
}else
it_pos++;
}
正確: code2
vector<string> vecFiles;
vector<string>::iterator it_pos;
//@todo 已下載檔案過濾
for (it_pos = vecFiles.begin(); it_pos != vecFiles.end(); ) {
string strTmp = *it_pos;
if( objDownHis.checkHisList( strTmp.c_str() ) ){ //判斷是否已下載過, 已下載則從列表刪除
g_Log << TIME << "file:[" << *it_pos << "] found "<< END; //
it_pos = vecFiles.erase(it_pos);
}else
it_pos++;
}
錯誤: code3
vector<string> vecFiles;
vector<string>::iterator it_pos;
//@todo 已下載檔案過濾
for (it_pos = vecFiles.begin(); it_pos != vecFiles.end(); it_pos++) {
string strTmp = *it_pos;
if( objDownHis.checkHisList( strTmp.c_str() ) ){ //判斷是否已下載過, 已下載則從列表刪除
g_Log << TIME << "file:[" << *it_pos << "] found "<< END; //
vecFiles.erase(it_pos);
}
}
code3 錯誤的原因為, vecFiles.erase(it_pos); 當前的it_pos已經被刪除了, 再下一次迴圈的時候 it_pos++, 訪問非法記憶體..
然後回過頭來看code1, vecFiles.erase(it_pos++); 在當前的it_pos已經被刪除的時候, it_pos已經指向下一個位置了. 雖然這裡邏輯上是錯誤的. 但是利用c語法的特性產生了一個正確的結果, 算是一個技巧. 不算是一門技術.
code2, it_pos = vecFiles.erase(it_pos); erase刪除的時候, 也返回了下一個指標的位置,我們將這個位置保留了, 所以這種做法也是正確的.
另外一個移植性比較好的做法是remove_if 和一個仿函式.
仿函式可以是:
struct check {
check( Object * objDownHis ) : m_obj( objDownHis ) {}
check( const check & c ) : m_obj( c.m_obj ) {}
bool operator()(const string & s) const {
if ( m_obj->checkHisList( s.c_str() ) {
g_Log .........
return true;
}
return false;
}
Object * m_obj;
};
vecFiles.erase( std::remove_if( vecFile.begin(), vecFile.end(), check( &objDownHis ) );
鳴謝p大, lancey, jackz 排名不分先後.. 全按交流時間順序...