std :: transform中的分段错误

时间:2015-06-24 19:52:24

标签: c++ regex lambda boost-filesystem

我试图将解析出的文件名从正则表达式匹配转移到filesystem::path对象列表。

我相信匹配是有效的,因为for_each对于相同的迭代器和打印到控制台工作完美。但是,我在运行此代码时遇到了分段错误。我究竟做错了什么?我的lambda有错吗?

        namespace fs = boost::filesystem;
        std::forward_list<fs::path> results;
        std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
                       std::sregex_iterator(), results.begin(),
                       [&](const std::smatch& m)->fs::path{
            return root / fs::path(m[1].str());
        });

GDB向我展示了这一行作为错误的地方:

path& operator=(const path& p)
{
  m_pathname = p.m_pathname;
  return *this;
}

更新:找到解决方案 - 使用back_inserter(results)代替results.begin()。但是,为什么呢?

2 个答案:

答案 0 :(得分:6)

std::transform算法的第三个参数应该是应该写入值的范围起点的迭代器。具体来说,它通过使用转换后的值覆盖迭代器指向的范围内的值来工作。这意味着实际上必须在那里覆盖值才能覆盖。在你的情况下,你写的是一个空的forward_list,所以没有什么可写的,因此崩溃。

要解决此问题,请考虑使用back_inserter替换最后一个参数,这将自动创建在生成值时所需的空间:

std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
               std::sregex_iterator(),
               back_inserter(results), // <--- This is new
               [&](const std::smatch& m)->fs::path{
        return root / fs::path(m[1].str());
});

更一般地说,据我所知,<algorithm>中写入输出范围的所有算法都假设有可用于覆盖该范围的值。如果不是这种情况,请考虑使用back_inserter或其他类型的插入迭代器,它将自动创建您需要的空间。

希望这有帮助!

答案 1 :(得分:2)

您的输出迭代器是一个简单的results.begin(),可能是== results.end()。这里的线索是在尝试分配结果时失败。

您要么找到back_inserter,要么使用已经分配了足够空间的容器(只有在您知道提前转换了多少项目时才能使用)。

具体来说,请考虑第一个重载here的示例实现。

该行

*d_first++ = op(*first1++);

要求目标迭代器已经有效。如果按照建议== end(),则整个操作都是非法的。

相关问题