2016-09-07 62 views
0

給出的例子目錄樹來進行測試:Visual Studio recursive_directory_iterator.pop()是否被破壞?

Root 
    A 
     A1 
     A2 
    B 
     B1 
     B2 

我想遞歸地列舉目錄,但完全跳過目錄A的處理。

根據MSDN文檔代碼類似於下面的東西應該做的工作:

void TestRecursion1() 
{ 
    path directory_path("Root"); 
    recursive_directory_iterator it(directory_path); 

    while (it != recursive_directory_iterator()) 
    { 
     if (it->path().filename() == "A") 
     { 
     it.pop(); 
     } 
     else 
     { 
     ++it; 
     } 
    } 
} 

...事實並非如此。 MSDN的recursive_directory_iterator.pop()指出

If depth() == 0 the object becomes an end-of-sequence iterator. 
Otherwise, the member function terminates scanning of the current 
(deepest) directory and resumes at the next lower depth. 

實際發生的是,由於在流行短路試驗(+),如果「深度== 0」無任何響應,迭代器既不增加也不它成爲序列迭代器的終點,程序進入無限循環。

這個問題似乎是在語義上彈出()是爲了將樹的處理分流到高於當前級別的下一級,而在本例中我希望跳過A的處理並繼續在B處處理。第一個問題是這兩個目錄(A和B)存在於樹中的同一級別,第二個問題是該級別也是樹的最高級別,所以沒有更高的級別來恢復處理。儘管如此,它仍然像是一個bug,pop()未能將迭代器設置爲序列結束迭代器,從而導致無限循環。

經過這次測試,我推斷如果我不能直接彈出()A,我應該至少能夠從A的任何子節點彈出()並獲得類似的結果。我用下面的代碼測試此:

template<class TContainer> 
bool begins_with(const TContainer& input, const TContainer& match) 
{ 
    return input.size() >= match.size() 
     && equal(match.begin(), match.end(), input.begin()); 
} 

void TestRecursion2() 
{ 
    path base_path("C:\\_Home\\Development\\Workspaces\\Scratch \\TestDirectoryRecursion\\bin\\Debug\\Root"); 
    recursive_directory_iterator it(base_path); 

    while (it != recursive_directory_iterator()) 
    { 
     string relative_path = it->path().parent_path().string().substr(base_path.string().size()); 
     cout << relative_path << "\n"; 

     if (begins_with(relative_path, string("\\A"))) 
     { 
     it.pop(); 
     } 
     else 
     { 
     cout << it->path().filename() << " depth:" << it.depth() << "\n"; 
     ++it; 
     } 
    } 
} 

在這裏,我測試正在處理每一個項目,以確定其是否父是root \ A,如果是調用pop()方法。即使這不起作用。測試正確地標識了樹中的一個節點是否是A的子節點,並相應地調用pop(),但即使在更深層次上,pop()仍然無法增加迭代器,從而導致無限循環。更重要的是,即使這個做了的工作,它仍然是非常不受歡迎的,因爲不能保證枚舉子節點的順序,所以儘管測試檢查特定節點是否是A的子節點,因爲這些節點可能作爲間接的孩子,你仍然可以最終處理好數量的A。

我認爲我的下一步行動是放棄使用此recursive_directory_iterator並使用標準directory_iterator手動驅動遞歸,但似乎我應該能夠實現我更需要recursive_directory_iterator的簡單功能,每一次都會被擋住。所以我的問題是:

是否recursive_directory_iterator.pop()方法被破壞?

如果不是我如何使用它來跳過處理目錄?

回答

0

是不是你想要的代碼更像以下,使用disable_recursion_pending()

while (it != recursive_directory_iterator()) 
    { 
     if (it->path().filename() == "A") 
     { 
     it.disable_recursion_pending(); 
     } 
     ++it; 
    } 
+0

這的確行得通,但disable_recursion_pending僅在VS2015中可用,我試圖在VS2012中做到這一點。 disable_recursion_pending的文檔聲明它「在no_push中存儲true」,VS2012有一個no_push方法,但其效果是禁止每個後續樹節點的遞歸,而不僅僅是您調用它的那個節點。這似乎也完全破壞了,因爲這不是tr2文件系統庫所基於的Boost實現的行爲。在Boost實現中,no_push只適用於迭代器當前指向的節點。 – Neutrino

+0

您引用的'pop()'的描述是針對VS2015的 - 對VS2012的'pop()'的描述只是說「停止讀取當前子目錄並遞增迭代器」 - 不保證隨後會發生什麼。 – Jeremy

+0

你說得對,我在VS2012和VS2015測試了這個,我從錯誤的頁面複製了文檔片段。儘管如此,它仍然不會增加VS2012中的迭代器。 – Neutrino