set_difference、set_intersection 和 set_union 的就地版本
Posted
技术标签:
【中文标题】set_difference、set_intersection 和 set_union 的就地版本【英文标题】:Inplace versions of set_difference, set_intersection and set_union 【发布时间】:2017-06-04 22:11:52 【问题描述】:我实现了set_union
、set_intersection
和set_difference
的版本,它们采用排序容器和排序范围(不得在容器内),并将操作结果写入容器。
template<class Container, class Iter>
void assign_difference(Container& cont, Iter first, Iter last)
auto new_end = std::set_difference( // (1)
cont.begin(), cont.end(), first, last, cont.begin());
cont.erase(new_end, cont.end());
template<class Container, class Iter>
void assign_intersection(Container& cont, Iter first, Iter last)
auto new_end = std::set_intersection( // (2)
cont.begin(), cont.end(), first, last, cont.begin());
cont.erase(new_end, cont.end());
template<class Container, class Iter>
void assign_union(Container& cont, Iter first, Iter last)
auto insert_count = last - first;
cont.resize(cont.size() + insert_count); // T must be default-constructible
auto rfirst1 = cont.rbegin() + insert_count, rlast1 = cont.rend();
auto rfirst2 = std::make_reverse_iterator(last);
auto rlast2 = std::make_reverse_iterator(first);
rlast1 = std::set_union( // (3)
rfirst1, rlast1, rfirst2, rlast2, cont.rbegin(), std::greater<>());
cont.erase(std::copy(rlast1.base(), cont.end(), cont.begin()), cont.end());
目标是:
如果容器有足够的容量来保存结果,则不执行分配。 否则只会执行一次分配,以使容器有能力保存结果。正如您在标记为 (1)、(2) 和 (3) 的行中看到的,相同的容器被用作这些 STL 算法的输入和输出。假设这些 STL 算法的常规实现,此代码可以工作,因为它只写入已处理的容器部分。
正如 cmets 中所指出的,标准不保证此方法有效。 set_union
、set_intersection
和 set_difference
要求结果范围不与输入范围之一重叠。
但是,是否存在破坏代码的 STL 实现?
如果您的回答是肯定的,请提供破坏代码的三种使用的 STL 算法之一的一致实现。
【问题讨论】:
即使今天的符合标准的实现不会破坏代码,如果标准中没有保证,那么简单地升级编译器可能会导致它破坏。甚至不同的优化设置或任何其他编译器标志。我认为您必须提供自己的实现才能确定。 这些算法的实现只需要几行代码,因此您可以编写一个破坏代码的算法。 我的标准副本包含所有这些算法的以下文本:Requires: The resulting range shall not overlap with either of the original ranges.
我不认为你可以保证它有效。
【参考方案1】:
符合标准的实现可以检查set_intersection
的参数 1 和 5 是否相等,以及它们是否正在格式化您的硬盘。
如果你违反了要求,你的程序的行为就不受标准的约束;你的程序格式不正确。
在某些情况下,UB 可能值得冒险和付出代价(审计所有编译器更改和汇编输出)。我不明白这里的重点;自己写。当您违反要求时,std 库提出的任何花哨的优化都可能导致问题,并且正如您所指出的,天真的实现很简单。
【讨论】:
【参考方案2】:根据我的经验,不要在您正在迭代的容器上写入内容。一切都可能发生。一般来说,这很奇怪。
正如@Yakk 所说,这听起来很糟糕。就是这样。从你的代码库中删除的东西安然入睡。
如果您真的需要这些功能,我建议您自己编写内部循环(例如:std::set_intersection
的内部),以处理您的算法工作所需的约束。
我不认为寻找一个不起作用的 STL 实现是正确的方法。这听起来不像是一个长期的解决方案。从长远来看:标准应该是您的参考,正如有人已经指出的那样,您的解决方案似乎无法正确处理它。
我的 2 美分
【讨论】:
以上是关于set_difference、set_intersection 和 set_union 的就地版本的主要内容,如果未能解决你的问题,请参考以下文章