C++异步目录遍历中局部变量vect为何能汇总所有目录的文件?
C++异步目录遍历中局部变量vect为何能汇总所有目录的文件?
别困惑啦,我来给你一步步拆解这段代码的逻辑,你马上就能明白——每个ListDirectory2函数里的vect确实是局部变量,但它们通过显式的结果合并,最终把所有文件汇总到了顶层返回值里,根本不是什么全局变量的魔法!
咱们来捋清楚整个流程:
- 每次调用
ListDirectory2时,都会创建一个属于自己的局部vect,这个变量只在当前函数调用的栈帧里存在,和其他调用的vect完全是独立的,这点你没看错。 - 函数先遍历当前目录的条目:
- 如果是普通文件,直接加到当前的
vect里; - 如果是子目录,就用
std::async异步启动一个新的ListDirectory2调用去处理这个子目录,把返回的std::future存在finalVect里。
- 如果是普通文件,直接加到当前的
- 重点来了!遍历完当前目录的直接条目后,代码会遍历
finalVect里的所有异步任务:- 用
fut.get()等待子任务完成,拿到子目录遍历返回的文件列表lst(这其实是子目录对应的ListDirectory2调用里的局部vect的副本); - 然后通过
std::copy(lst.begin(), lst.end(), std::back_inserter(vect));,把lst里的所有元素追加到当前函数的局部vect末尾。
- 用
- 当当前函数的所有子任务都处理完,它就把自己的
vect返回给上层调用——上层调用同样会把这个返回的列表,追加到上层自己的局部vect里。
就这样,一层一层递归/异步调用,每个局部vect都把自己目录的文件,加上所有子目录返回的文件汇总起来,最终最顶层的调用(main里的那个)就拿到了所有目录的文件列表。
举个简单例子:假设你有C:/Test下有文件A,还有子目录Sub下有文件B。那么:
- 处理
C:/Test的ListDirectory2调用,先把A加到自己的vect; - 然后异步调用处理
Sub,那个调用的局部vect里有B,返回给上层; - 上层把B追加到自己的
vect,现在这个vect里就有A和B了,最后返回给main。
所以核心不是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'; } }
备注:内容来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

