进一步的 std::set 问题

发布于 2024-07-21 00:19:47 字数 623 浏览 2 评论 0原文

我之前问过这个问题。 我对 std::set 很感兴趣,但我有另一个令人困惑的场景。

也就是说,以下代码对于 T=std::vector 和 T=std::set 是否合法、可移植 C++:

template <typename T>
void remove_elements(T& collection, int removal_value)
{
    typename T::iterator new_end = 
        std::remove(collection.begin(), collection.end(), removal_value);
    collection.erase(new_end, collection.end());
}

根据 SGI 参考,set::iterator 和 set::const_iterator 是相同的,所以我不知道如果这是合法的。 但是,我似乎无法找到另一种方法来获得我需要的操作,无论类型如何。 我可以诉诸模板专门化,但是最好不必首先专门化。

I asked this question earlier. I am intrigued by std::set but I have another confusing scenario.

Namely, is the following code legal, portable c++ for T=std::vector and T=std::set:

template <typename T>
void remove_elements(T& collection, int removal_value)
{
    typename T::iterator new_end = 
        std::remove(collection.begin(), collection.end(), removal_value);
    collection.erase(new_end, collection.end());
}

According to the SGI reference, set::iterator and set::const_iterator are the same, so I don't know if this is legit. However, I can't seem to find another way to get the operation I need to work regardless of type. I could resort to template specialization, however it would be nice not to have to specialize in the first place.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

地狱即天堂 2024-07-28 00:19:47

擦除-删除习惯用法仅适用于序列容器。 对于标准关联容器,它不起作用,而且解决方案也不是那么简单。

两种方法:

  1. 使用remove_copy_if复制所有
    值到另一个临时值
    容器,然后交换内容
    原来的容器与那些
    临时的一个。 [请参阅我对相关问题的答案]
  2. 另一个是循环步行
    当您将迭代器传递给擦除时,容器元素和 post 会递增迭代器。

有关更多详细信息,请参阅此问题: remove_if 相当于 std::map

另外,请参阅第 9 项。在 Scott Meyers 的《Effective STL》中仔细选择擦除选项。

erase-remove idiom works only for sequence containers. For the standard associative containers it will not work and the solution is not so straightforward.

Two approaches :

  1. Use remove_copy_if to copy all the
    values into another temporary
    container and then swap the contents
    of the original container with those
    of temporary one. [Refer my answer to related Q]
  2. The other one would be loop to walk
    the container elements and post increment the iterator when you pass it to erase.

Refer this Q for more details: remove_if equivalent for std::map

Also, refer Item 9. Choose carefully among erasing options from Effective STL by Scott Meyers.

韬韬不绝 2024-07-28 00:19:47

不,它不适用于 std::set,因为 std::remove() 的要求之一是迭代器是可变迭代器,并且 < code>std::set 的迭代器是不可变的。

不幸的是,我没有任何好的替代方案可以建议。 您可以做的一件事是使用 std::find() 查找元素出现的迭代器,然后使用 .erase() 方法迭代器(存在于 std::vector 和 std::set 中)来擦除它; 并继续这样做,直到不再有此类元素。 但这可能非常低效,O(n^2) 而不是 O(n)。

No, it won't work for std::set, because one of the requirements of std::remove() is that the iterator be a mutable iterator, and std::set's iterators are not mutable.

I don't have any good alternatives to suggest, unfortunately. One thing you could do is maybe use std::find() to find an iterator to an occurrence of the element, and then use the .erase() method on the iterator (which is present in both std::vector and std::set) to erase it; and keep doing it until there are no more such elements. But this might be very inefficient, O(n^2) instead of O(n).

一抹微笑 2024-07-28 00:19:47

我认为“正确”的答案是为 std::set 重载 remove_elements 。 由于集合是有序的并且不包含重复项,因此删除等于removal_value的元素比向量或通用序列简单得多。 你并不真的想对所有事情使用相同的算法,即使你可以:

template <typename T>
void remove_elements(T& collection, const typename T::value_type& removal_value)
{
    typename T::iterator new_end = 
        std::remove(collection.begin(), collection.end(), removal_value);
    collection.erase(new_end, collection.end());
}

template<typename T>
void remove_elements(std::set<T>& collection, const T& removal_value)
{
    collection.erase(removal_value);
}

我有点担心这些是否模糊,但在最明显的用例中,它们似乎对我来说工作正常。

如果您需要担心 std::set 之外的其他唯一排序关联容器,这会有点痛苦。 您正在进入 std::swap 领域,您实现的每个类都必须提供remove_elements 的重载。 但由于 set 是您询问的唯一类,我认为这是您实际使用的唯一棘手的情况,至少目前是这样。 如有必要,您可以使用特征根据容器的属性选择正确的算法版本。

I think the "right" answer is to overload remove_elements for std::set. Since set is ordered and contains no duplicates, removing elements equal to removal_value is much simpler than for vector or for generic sequences. You don't really want to use the same algorithm for everything, even if you could:

template <typename T>
void remove_elements(T& collection, const typename T::value_type& removal_value)
{
    typename T::iterator new_end = 
        std::remove(collection.begin(), collection.end(), removal_value);
    collection.erase(new_end, collection.end());
}

template<typename T>
void remove_elements(std::set<T>& collection, const T& removal_value)
{
    collection.erase(removal_value);
}

I'm slightly concerned about whether these are ever ambiguous, but in the most obvious use case they seem to work OK for me.

This is a bit of a pain if you have other Unique Sorted Associative Containers than std::set to worry about. You're moving into std::swap territory, where every class you implement has to provide an overload of remove_elements. But since set is the only class you're asking about, I assume it's the only tricky case you're actually using, at least for now. If necessary you can use traits to select the right version of the algorithm based on the properties of the container.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文