【问题标题】:C++ directory item iteration without exceptionsC++目录项迭代无异常
【发布时间】:2021-05-31 15:46:37
【问题描述】:

在 C++17 中,迭代某个目录 dir 中的项目变得很容易:

for ( auto& dirEntry: std::filesystem::directory_iterator(dir) )
{
  if ( !dirEntry.is_regular_file() ) continue;
...

不幸的是,这种方式可能会引发异常,我想在我的程序中避免这种情况。

不抛出异常的迭代也是可以的:

std::error_code ec;
const std::filesystem::directory_iterator dirEnd;
for ( auto it = std::filesystem::directory_iterator( dir, ec ); !ec && it != dirEnd; it.increment( ec ) )
{
  if ( !it->is_regular_file( ec ) ) continue;
...

但它在 C++ 中更加冗长。例如,我不能使用基于范围的 for。这个更大的代码大小对我来说真的很重要,因为我有很多地方需要迭代。 有没有办法简化代码迭代目录项,同时又能避免异常?

【问题讨论】:

  • 当然。像上面那样编写一个例程,然后从任何地方调用它。
  • 您如何期望基于范围的 for 循环指示错误?您无权访问迭代器,也不能抛出异常。不过,您也许可以编写一个包装类,将目录条目视为结束迭代器(并可能提供错误信息)。
  • 注意两个版本都可能抛出std::bad_alloc。 (/me 不喜欢文件系统接口)。
  • 我唯一的建议是using 别名...? using DirIt = std::filesystem::directory_iterator;你可能已经想到了,但我只是以防万一。

标签: c++ c++17 c++-standard-library std-filesystem


【解决方案1】:

我认为可以创建一个安全的包装迭代器,其中运算符++不会抛出异常,如下

// object of this struct can be passed to range based for
struct safe_directory
{
    std::filesystem::path dir;
    std::error_code & ec;
};

//iterator of directory items that will save any errors in (ec) instead of throwing exceptions
struct safe_directory_iterator
{
    std::filesystem::directory_iterator it;
    std::error_code & ec;
    safe_directory_iterator & operator ++() { it.increment( ec ); return * this; }
    auto operator *() const { return *it; }
};

safe_directory_iterator begin( const safe_directory & sd )
{
    return safe_directory_iterator{ std::filesystem::directory_iterator( sd.dir, sd.ec ), sd.ec };
}
 
std::filesystem::directory_iterator end( const safe_directory & )
{
    return {};
}

bool operator !=( const safe_directory_iterator & a, const std::filesystem::directory_iterator & b )
{
    return !a.ec && a.it != b;
}

那么就可以在这样的程序中使用了

int main()
{
    std::error_code ec;
    safe_directory sdir{ std::filesystem::current_path(), ec };

    for ( auto dirEntry : sdir )
    {
        if ( dirEntry.is_regular_file( ec ) )
            std::cout << dirEntry.path() << std::endl;
    }
}

查看在线编译器中的示例:https://gcc.godbolt.org/z/fb4qPE6Gf

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多