2009-10-22 47 views
48

我有一個std :: vector m_vPaths;我會迭代這個向量並隨時調用:: DeleteFile(strPath)。如果我成功刪除了該文件,我將從矢量中刪除它。我的問題是我可以避開使用兩個向量?是否有不同的數據結構可能更適合我需要做的事情?迭代向量,當我去時刪除某些項目

例子: 使用迭代器幾乎做我想做的事情,但問題是一旦你使用迭代器擦除,所有迭代器變得無效。

std::vector<std::string> iter = m_vPaths.begin(); 
    for(; iter != m_vPaths.end(); iter++) { 
     std::string strPath = *iter; 
     if(::DeleteFile(strPath.c_str())) { 
      m_vPaths.erase(iter); 
       //Now my interators are invalid because I used erase, 
       //but I want to continue deleteing the files remaining in my vector.  
     } 
    } 

我可以用兩個向量和我將不再有問題,但有沒有這樣做我想要做的更好的,更有效的方法?

順便說一句,櫃面目前還不清楚,m_vPaths聲明如下(在我的課):

std::vector<std::string> m_vPaths; 
+0

此外,我不''真正的情況下,它使用什麼樣的數據結構,如果有更好的東西比矢量讓我知道。我不認爲std :: queue或std :: list有任何幫助我的東西(雖然我可能是錯的:) – cchampion 2009-10-22 01:43:23

回答

67

退房std::remove_if

#include <algorithm> // for remove_if 
#include <functional> // for unary_function 

struct delete_file : public std::unary_function<const std::string&, bool> 
{ 
    bool operator()(const std::string& strPath) const 
    { 
     return ::DeleteFile(strPath.c_str()); 
    } 
} 

m_vPaths.erase(std::remove_if(m_vPaths.begin(), m_vPaths.end(), delete_file()), 
       m_vPaths.end()); 

使用std::list制止無效的迭代器的問題,儘管你失去了隨機訪問。 (和緩存性能,在一般情況)


根據記錄,你會實現你的代碼將是這樣:

typedef std::vector<std::string> string_vector; 
typedef std::vector<std::string>::iterator string_vector_iterator; 

string_vector_iterator iter = m_vPaths.begin(); 
while (iter != m_vPaths.end()) 
{ 
    if(::DeleteFile(iter->c_str())) 
    { 
     // erase returns the new iterator 
     iter = m_vPaths.erase(iter); 
    } 
    else 
    { 
     ++iter; 
    } 
} 

但是,你應該使用std::remove_if(重新發明輪子是壞的)。

90

erase()方法返回一個新的(有效的)迭代器,該迭代器指向刪除之後的下一個元素。你可以使用這個迭代繼續循環:

std::vector<std::string>::iterator iter; 
for (iter = m_vPaths.begin(); iter != m_vPaths.end();) { 
    if (::DeleteFile(iter->c_str())) 
     iter = m_vPaths.erase(iter); 
    else 
     ++iter; 
} 
+2

微妙。我幾乎低估了這一點,因爲我認爲擦除會使以下迭代器無效。感謝您的鏈接。 – 2009-10-22 13:57:32

+0

但是,這種方法不適用於所有STL容器(特別是std :: map),而擦除(範圍)/刪除組合適用於任何STL容器。 – 2009-10-22 19:10:18

+3

對於'std :: map',您可以使用'erase(iter ++);'因爲'erase'不會使其他迭代器失效,而不會使其他迭代器失效。 – sth 2009-10-22 19:18:51

7

給刪除文件的時候,它可能並不重要,但我還是勸通過向後矢量迭代 - 這樣你」通常從(接近)向量的末尾刪除項目。刪除項目所用的時間與向量中的項目數量成正比。如果(例如)有一個包含100個文件名的矢量,並且您成功刪除了所有這些文件名,則會在該過程中將最後一個元素複製100次(並將第二個元素複製到最後一個元素99次,依此類推)。

OTOH,如果您從最後開始並向後工作,只要刪除文件成功即可不復制。您可以使用反向迭代器向後遍歷向量,而不會改變其他任何東西。例如,使用remove_if的GMan代碼應該繼續工作(只需要稍微快點),只需將rbegin()替換爲begin(),然後將rend()替換爲end。

另一種可能是使用deque而不是矢量 - deque可以在最後的這個集合的開始時間內擦除項目。

+0

將第n個物品移動到第n個索引不是更好嗎?我們只需要索引位置值,一個用於第n個物品位置,另一個用於第n個索引。這將確保所有優質項目向前移動,一旦完成,我們可以將矢量調整爲n個元素(不確定是否支持)。至多,當第一個元素被刪除時,n-1交換髮生。 – saurabheights 2017-05-28 10:10:05