Как я могу удалить элемент из набора в C ++, не удаляя его?


April 2019


62 раз


Использование зОго :: установлен в C ++, единственный способ, которым я могу найти, чтобы удалить элемент из набора состоит в использовании методы стирания. Это удаляет элемент в вопрос, который я не хочу, чтобы это произошло. Единственный способ, которым я могу думать, чтобы удалить элемент из набора, не удаляя его было бы создать новый набор и добавить все элементы старого набора к нему итеративно, убедившись, что не добавить элемент, который должен быть удален из набор, затем удалить старый набор.

Есть ли уборщик способ сделать это?

2 ответы


Moving an object out of a set

You can use extract to remove the corresponding node from the set. This gives you a handle to the node. Once you have the handle, you can move the item out of the handle.

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());

Alternatively, if you already have the iterator to the node, you can write it like this:

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

Moving the value transfers ownership of any resources owned by the value. For example, if the set contains a string, the contents of the string won't be deleted, and any iterators to the string won't be invalidated.

The caveat of this is that if you had pointers or references to the object from when it was still in the set, these will be invalidated.

Extracting the object itself without a move and without invalidating any pointers or references to the object

This is the less common case, but if you had a reference or pointer to the object in the set, you may want to do this.

Again, we can use the extract function:

auto node_handle = s.extract(my_object);


auto node_handle = s.extract(my_iterator); 

You can access the stored object with node_handle.value(), which returns a reference to the object. The object won't be deleted until the node_handle is deleted, and if you need to extend it's lifetime further, you can return the node_handle from a function without the object being deleted.


You can't remove an item from a set without deleting it. Sets own their members. If the member is removed from the set, it doesn't exist anymore. If you want to be able to remove something without deleting it, don't add it to a set.

Imagine if you have int x[5]; x[2]=2;. How can you get x[2] out of the array? What would that even mean? You can, of course, construct a new integer with the same value, int j = x[2];. But that's a new object (with the same value) that is not extending the life of the existing object.

Depending on what your outer problem is, there might be a solution. For example, you could add a std::unique_ptr to an object into a set and then you can destroy that std::unique_ptr without destroying the object it points to be constructing a new std::unique_ptr to the same underlying object.