迭代它时从集合中擦除的最有效方法

Aff*_*Owl 5 c++

迭代它时从集合中删除的最有效方法是什么?以下是我想到的两种方法,它们之间最好的方法是什么?还有另一种更好的方法吗?

void WaitForFiles(std::set<string> files) {
  while (files.size() > 0) {
    std::set<string> found_files;
    for (const auto& file : files) {
      if (Exists(file)) {
        found_files.insert(file);
      }
    }
    for (const auto& found_file : found_files) {
      files.erase(file);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用set_difference:

void WaitForFiles(std::set<string> files) {
  while (files.size() > 0) {
    std::set<string> found_files;
    for (const auto& file : files) {
      if (Exists(file)) {
        found_files.insert(file);
      }
    }
    std::set<string> difference;
    std::set_difference(files.begin(), files.end(),
                        found_files.begin(), found_files.end(),
                        std::inserter(difference, difference.end()));
    files = difference;
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意以下崩溃:

void WaitForFiles(std::set<string> files) {
  while (files.size() > 0) {
    for (const auto& file : files) {  // <-- seg fault after first erase
      if (Exists(file)) {
        files.erase(file);
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

为了确定效率,请记住,在我的情况下,文件可能需要30分钟才能生成,因此Exists函数将被多次调用,并且与迭代循环的次数相比,文件集不会经常更改过度.

Chr*_*rew 11

从基于范围的for循环中的集合中擦除是未定义的行为(即使它似乎工作).基于范围的for循环在内部使用迭代器,并且擦除元素使迭代器无效.

但是std::set::erase返回一个有效的迭代器到下一个元素,std::set所以你可以使用显式的迭代器循环:

for(auto itr = files.cbegin(); itr != files.cend();) {
  if (exists(*itr)) {
    std::cout << "Found file: " << *itr << "\n";
    itr = files.erase(itr);
  } else
    ++itr;
}
Run Code Online (Sandbox Code Playgroud)

现场演示.