如何在C ++中从集合中删除项目而不删除它?

时间:2019-04-10 22:14:11

标签: c++ stl set

在C ++中使用std :: set,我发现从集中删除项目的唯一方法是使用擦除方法。这将删除有问题的项目,我不想发生。我能想到的从集合中删除项目而不删除它的唯一方法是创建一个新集合,并迭代地将旧集合的所有项目添加到其中,确保不要添加需要从中删除的项目。集合,然后删除旧集合。

是否有一种更清洁的方法?

2 个答案:

答案 0 :(得分:2)

您不能从集中删除某项,而不能删除它。设置自己的成员。如果将该成员从集合中删除,则该成员不再存在。如果您想删除某些内容而不删除它,请不要将其添加到集合中。

想象一下您是否有int x[5]; x[2]=2;。如何从阵列中取出x[2]?那甚至意味着什么?当然,您可以构造一个具有相同值int j = x[2];的新整数。但这是一个新对象(具有相同的值),不会延长现有对象的寿命。

根据您的外部问题,可能有解决方案。例如,可以将一个对象std::unique_ptr添加到集合中,然后可以销毁该std::unique_ptr,而不必销毁它指向同一基础对象构造新的std::unique_ptr的对象。

答案 1 :(得分:1)

将对象移出集合

您可以使用extract从集合中删除相应的节点。这为您提供了该节点的句柄。握住手柄后,您可以将其移出手柄。

template<class T>
T find_and_remove(std::set<T>& s, T const& elem) {
    auto iterator = s.find(elem); 
    if(iterator == s.end() {
        throw std::invalid_argument("elem not in set"); 
    }
    // Remove element, return node handle
    auto node_handle = s.extract(iterator);
    return std::move(node_handle.value());
}

或者,如果您已经有该节点的迭代器,则可以这样编写:

template<class T>
T remove_from_set(std::set<T>& s, std::set<T>::iterator it) {
    return std::move(s.extract(it).value());
}

移动值会转移该值所拥有的任何资源的所有权。例如,如果集合包含一个字符串,则不会删除该字符串的内容,并且不会使该字符串的任何迭代器无效。

需要注意的是,如果从对象仍位于集合中起就具有指向该对象的指针或引用,则这些对象将无效。

无需移动即可提取对象本身,并且不会使对该对象的任何指针或引用无效

这是较不常见的情况,但是如果您对集合中的对象有引用或指针,则可能要这样做。

同样,我们可以使用extract函数:

auto node_handle = s.extract(my_object);

或者:

auto node_handle = s.extract(my_iterator); 

您可以使用node_handle.value()访问存储的对象,该对象返回对该对象的引用。在删除node_handle之前,不会删除该对象;如果需要延长其生存期,可以从函数中返回node_handle,而不会删除该对象。