这是一个在C++中使用异步任务完成目录树列表的程序。
我的问题是在每个函数调用中,变量'vect'被创建为一个局部变量,在每个函数调用中,我们有一个目录中的文件列表,但在最后所有目录中的所有文件都被返回到main!这怎么可能?
我的意思是为什么'vect'变量是每个函数调用的局部变量,却保存了由单独的函数调用生成的每个目录的文件名?!这个'vect'的行为就像它是一个全局变量一样。是因为“std::copy”吗?我不明白!
#include <algorithm>
#include <filesystem>
#include <future>
#include <iostream>
#include <vector>
typedef std::vector<std::filesystem::directory_entry> vectDirEntry;
vectDirEntry ListDirectory2(std::filesystem::directory_entry&& dirPath)
{
std::vector<std::future<std::vector<std::filesystem::directory_entry>>> finalVect;
vectDirEntry vect;
for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(dirPath))
{
if (entry.is_directory())
{
std::future<vectDirEntry> fut = std::async(std::launch::async, &ListDirectory2, entry);
finalVect.push_back(std::move(fut));
}
else if (entry.is_regular_file())
{
vect.push_back(entry);
}
}
std::for_each(finalVect.begin(), finalVect.end(), [&](std::future<std::vector<std::filesystem::directory_entry>>& fut)
{
vectDirEntry lst = fut.get();
std::copy(lst.begin(), lst.end(), std::back_inserter(vect));
}
);
return vect;
}
int main()
{
const std::filesystem::directory_entry root = std::filesystem::directory_entry("C:/Test");
std::future<std::vector<std::filesystem::directory_entry>> fut = std::async(std::launch::async, &ListDirectory2, root);
auto result = fut.get();
for (std::filesystem::directory_entry& item : result)
{
std::cout << item << '\n';
}
}
2条答案
按热度按时间gr8qqesn1#
每个递归调用都有一个单独的
vect
,但是当你返回它时,从std::async
生成的future会提供每个调用的vect
。对于每个
std::async
分派的期货,您使用它们的vect
来填充父项的vect
(它反过来返回)。该代码中的
lst
是由您的一个递归调用返回的vect
。该std::copy
中的vect
是来自 * 当前 *ListDirectory2
调用的vect
,通过引用隐式接收(因为您以[&]
开始lambda定义,这意味着未在λ内声明的任何被引用的变量是对外部范围中的变量的隐式引用)。这里没什么异常在每次返回之前,您显式地从子
vect
复制到父vect
中,最终在最顶层的ListDirectory2
调用中构建最终的vect
,该调用包含来自每个递归调用的结果。顺便说一句,您正在执行一些并非绝对必要的复制,您可以通过将
std::copy
替换为std::move
来避免至少其中的一些复制(除了从r值引用r值的单参数版本之外,还有一个等效于std::copy
的三参数版本,它从源代码移动;由于lst
参数在每次函数调用结束时过期,因此清空它没有坏处)类似的更改可以是using theinsert
method ofvect
andstd::make_move_iterator
(通过允许向量在每次批量移动之前批量调整大小,可能会稍微快一些),但从std::copy
到std::move
的简单交换是最低限度的解决方案,应该足够快。ilmyapht2#
您观察到的情况与
async
调用无关,而是由于递归。下面是一个流程图,描述了3个目录级别,每个
vect
都有一个唯一的名称(它们是程序中唯一的示例)。当调用返回到
main
时,vect
将因此被填充以从起始目录开始的所有文件。