【问题标题】:meaning of boost::filesystem3::detail::dir_itr_imp in boost::shared_ptr dereferenceboost::filesystem3::detail::dir_itr_imp 在 boost::shared_ptr 取消引用中的含义
【发布时间】:2017-01-03 10:27:27
【问题描述】:

我正在使用以下代码列出目录:

for ( const auto& fileEntry : boost::make_iterator_range( boost::filesystem::directory_iterator( some_directory ), {} ) )
{
    const boost::filesystem::path tmpFullName = fileEntry.path();

    if ( boost::filesystem::exists( tmpFullName ) &&
        boost::filesystem::is_regular_file( tmpFullName ) &&
        (boost::filesystem::extension( tmpFullName ) == ".doc") )
    {
        processFile( tmpFullName.string() );
    }
}

我偶尔看到以下错误

/boost/1.47.0/include/boost-1_47/boost/smart_ptr/shared_ptr.hpp:420: T* boost::shared_ptr::operator->() const [with T = boost::filesystem3::detail::dir_itr_imp]: 断言 `px != 0' 失败。

在我的代码中,我没有定义任何 boost shared_ptr 而是只使用 std::unique_ptr。 因此,我认为潜在的问题在于上述列表函数。

有人可以仔细检查一下这个功能,看看这里是否有任何潜在的问题吗?

【问题讨论】:

  • 最新版本的Boost是否出现问题?
  • 由于内部原因,我无法使用最新版本的Boost
  • 请注意,您可以使用较短的版本而无需明确指定范围:for ( const auto& fileEntry : boost::filesystem::directory_iterator{ some_directory } )

标签: c++ boost


【解决方案1】:

函数directory_iterator_increment()(在operations.cpp中)包含以下代码:

1940: if (temp_ec)
1941: {
1942:   it.m_imp.reset();
1943:   if (ec == 0)
1944:     BOOST_FILESYSTEM_THROW(
1945:       filesystem_error("boost::filesystem::directory_iterator::operator++",
1946:         it.m_imp->dir_entry.path().parent_path(),
1947:         error_code(BOOST_ERRNO, system_category())));
1948:   ec->assign(BOOST_ERRNO, system_category());
1949:   return;
1950: }

在第 1942 行重置后,第 1946 行取消引用 it.m_imp。这将导致观察到的行为。

编辑添加:

此问题已在后续版本中修复:https://svn.boost.org/trac/boost/ticket/5900

【讨论】:

    【解决方案2】:

    你用的是什么编译器?可能是您使用的 c++ 库版本与 boost 的不匹配。

    【讨论】:

    • gcc 版本是 4.9.2
    【解决方案3】:

    Boost 在目录迭代器内部使用shared_ptr,因为“shared_ptr 提供 InputIterators 所需的浅拷贝语义”(boost/filesystem/operations.hpp,第 924 行,来自 Boost v1.61)。在 v1.61 中,对于取消引用 end 迭代器的情况有一个明确的断言,但也许 v1.47 只是依赖于 shared_ptr 取消引用的断言。

    我的猜测是迭代器在某处无效。在这些情况下目录不存在的任何机会?也许发生了从另一个线程/进程对目录的更改?

    顺便说一句,v1.61 包含 begin()/end() 函数,用于在基于范围的 for 循环中启用 directory_iterator。也许它不在 v1.47 中,但如果是,我会指望它而不是明确使用 make_iterator_range()

    【讨论】:

    • 不可能目录不存在 b/c 它已在程序开始时检查过。假设director被改变并且不存在,我仍然需要想办法防止应用程序崩溃。
    • 你在哪一行得到断言?
    • /boost/1.47.0/include/boost-1_47/boost/smart_ptr/shared_ptr.hpp:420
    • 它没有给出我的代码中的行。相反,它会转储原始问题中发布的消息,然后崩溃。此外,我无法找到重复该问题的工作流程。这个问题几乎不会发生。但我知道问题确实存在并想解决它。
    • 调试器,使用它。
    【解决方案4】:

    您确定第一行中的 {} 正在生成您期望的结束迭代器吗?

    尝试显式构造它,看看它是否有所作为:

    boost::make_iterator_range(
        boost::filesystem::directory_iterator( some_directory ),
        boost::filesystem::directory_iterator()  // instead of '{}'
    )
    

    【讨论】:

    • 如果它不起作用,那么每次我运行代码时它都会失败。
    • 这具体取决于它如何“不起作用”(如果确实不起作用) - 特别是如果它导致 UB。你试过了吗?
    猜你喜欢
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-03
    • 1970-01-01
    • 2011-12-19
    相关资源
    最近更新 更多