是否可以使用std :: merge进行重叠范围

时间:2016-04-06 14:17:22

标签: c++ c++11 merge stl

我有一个算法,需要多次将set union应用于增长的整数集。为了提高效率,我将集合表示为已排序的向量,以便通过合并它们来获得它们的并集。

合并两个排序向量的经典方法是:

void inmerge(vector<int> &a, const vector<int> &b) {
  a.reserve(a.size() + b.size());
  std::copy(b.begin(), b.end(), std::back_inserter(a));
  std::inplace_merge(a.begin(), a.end() - b.size(), a.end());
}

不幸的是,由于分配开销,std::inplace_merge在这种情况下似乎比std::sort慢得多。最快的方法是直接使用std::merge输出到其中一个向量中。为了在阅读之前不写值,我们必须从最终开始,如下所示:

void inmerge(vector<int> &a, const vector<int> &b) {
  a.resize(a.size() + b.size());
  orig_a_rbegin = a.rbegin() + b.size();
  std::merge(orig_a_rbegin, a.rend(), b.rbegin(), b.rend(), a.rend(), [](int x, int y) { return x > y; });
}

可以确定merge的实现永远不会写出比读取更多的元素,因此这是一件安全的事情。不幸的是,C ++标准(甚至是C ++ 17草案)禁止这样做:

  

结果范围不得与原始范围重叠   的范围内。

如果我知道自己在做什么,可以忽略这个限制吗?

2 个答案:

答案 0 :(得分:3)

不,忽略标准的授权(或您正在使用的某些库的任何其他文档)永远都不行。您可能知道正在做什么,但是您确定知道正在做什么 - 或者可能在下一个版本中做什么?

例如,合并算法可以检测到您的至少两个范围是反向范围,打开它们(并打开或反转第三个),然后在另一个方向上进行合并。只要保留前置条件,就没有可观察到的差异,但由于反向迭代器的开销消失,可能会稍微快一点。但它真的会搞砸你的代码。

答案 1 :(得分:0)

简单说明:否。

稍微长一点:如果你忽略了标准的授权,你最终会进入Undefined Behavior域,你的编译器可以自由地做任何想做的事情。 这包括完全按照您的期望,什么都不做,崩溃程序,删除所有文件或召唤鼻子恶魔。那不是你想成为的地方。