給出的例子目錄樹來進行測試: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()方法被破壞?
如果不是我如何使用它來跳過處理目錄?
這的確行得通,但disable_recursion_pending僅在VS2015中可用,我試圖在VS2012中做到這一點。 disable_recursion_pending的文檔聲明它「在no_push中存儲true」,VS2012有一個no_push方法,但其效果是禁止每個後續樹節點的遞歸,而不僅僅是您調用它的那個節點。這似乎也完全破壞了,因爲這不是tr2文件系統庫所基於的Boost實現的行爲。在Boost實現中,no_push只適用於迭代器當前指向的節點。 – Neutrino
您引用的'pop()'的描述是針對VS2015的 - 對VS2012的'pop()'的描述只是說「停止讀取當前子目錄並遞增迭代器」 - 不保證隨後會發生什麼。 – Jeremy
你說得對,我在VS2012和VS2015測試了這個,我從錯誤的頁面複製了文檔片段。儘管如此,它仍然不會增加VS2012中的迭代器。 – Neutrino