std :: merge合并两个std :: vector coredump

dau*_*ama 5 c++ merge stl

以下代码最终以核心转储结束.我做错了什么?

std::vector<int> a;
a.push_back(1);
a.push_back(4);
a.push_back(7);
std::vector<int> b;
b.push_back(2);
b.push_back(5);
b.push_back(8);
std::vector<int> c;
c.clear();


std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());
for (it=c.begin(); it!=c.end(); ++it)
    std::cout << *it << endl;
Run Code Online (Sandbox Code Playgroud)

在我可以使用的stl或boost中是否还有其他合并功能?

谢谢!

Jon*_*rdy 10

问题是你c是空的,因为它是在没有元素的情况下初始化的,更不用说不必要的调用了clear().std::merge()输出迭代器作为其最后一个参数.如果c.begin()指的std::vector已经包含足够元素的开头,那么这不是问题 - 这些元素将被覆盖.实际上,您通过将值写入超出向量末尾的内存来调用未定义的行为.

为确保c元素有足够的空间,您可以这样做:

c.resize(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());
Run Code Online (Sandbox Code Playgroud)

但是,使用一个std::back_insert_iterator调用的输出迭代器更加惯用push_back().为了提高效率,您可以reserve()事先调用矢量.这确保了c只需要分配一次内存,而不是在调用期间增长std::merge().最终解决方案如下所示:

#include <iterator>

// ...

c.reserve(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));
Run Code Online (Sandbox Code Playgroud)

  • @Luc`back_inserter`变体仍然需要调用`push_back`,而push_back`又需要检查长度(冗余,现在).我不知道收支平衡在哪里,但我很确定这意味着`reserve`变体对于原始类型来说仍然更快. (2认同)

Arm*_*yan 4

std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));
                                                   ^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

问题是,如果您传递c.begin(),合并函数将开始将值写入*c.begin()*(c.begin() + 1),这会导致未定义的行为,包括核心转储。这里你有两个选择。

  • 确保c足够大以容纳合并要写入其中的所有值。例如,您可以c.resize(a.size()+b.size());在调用之前调用merge
  • 通过一个std::back_insert_iterator. 我的答案一开始就给出了它的例子。每次执行*it = xwhere itis a时back_insert_iterator,它都会 push_backx 到底层容器中。

有关后插入迭代器的信息可以在此处找到。back_inserter只是一个方便的函数,这样您就不必编写大量模板参数。