我有一个算法,需要多次将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草案)禁止这样做:
结果范围不得与原始范围重叠 的范围内。
如果我知道自己在做什么,可以忽略这个限制吗?
答案 0 :(得分:3)
不,忽略标准的授权(或您正在使用的某些库的任何其他文档)永远都不行。您可能知道您正在做什么,但是您确定知道库正在做什么 - 或者可能在下一个版本中做什么?
例如,合并算法可以检测到您的至少两个范围是反向范围,打开它们(并打开或反转第三个),然后在另一个方向上进行合并。只要保留前置条件,就没有可观察到的差异,但由于反向迭代器的开销消失,可能会稍微快一点。但它真的会搞砸你的代码。
答案 1 :(得分:0)
简单说明:否。
稍微长一点:如果你忽略了标准的授权,你最终会进入Undefined Behavior域,你的编译器可以自由地做任何想做的事情。 这包括完全按照您的期望,什么都不做,崩溃程序,删除所有文件或召唤鼻子恶魔。那不是你想成为的地方。