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_unionset_intersectionset_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_unionset_intersectionset_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 的就地版本的主要内容,如果未能解决你的问题,请参考以下文章

set_difference的介绍

includes,set_union,set_intersection,set_difference

STL相关问题

IndexError:列表索引超出范围(Python)

Set容器

深度理解STL之mapset