Как я могу удалить элемент из набора в C ++, не удаляя его? - PullRequest
1 голос
/ 11 апреля 2019

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

Есть ли более чистый способ сделать это?

Ответы [ 2 ]

2 голосов
/ 11 апреля 2019

Вы не можете удалить элемент из набора, не удаляя его. Устанавливает собственные члены. Если член удален из набора, он больше не существует. Если вы хотите иметь возможность удалить что-либо, не удаляя его, не добавляйте его в набор.

Представьте, если у вас есть int x[5]; x[2]=2;. Как вы можете получить x[2] из массива? Что бы это вообще значило? Конечно, вы можете создать новое целое число с тем же значением, int j = x[2];. Но это новый объект (с тем же значением), который не продлевает жизнь существующего объекта.

В зависимости от вашей внешней проблемы, может быть решение. Например, вы можете добавить std::unique_ptr к объекту в набор, а затем вы можете уничтожить этот std::unique_ptr, не уничтожая объект, на который он указывает, чтобы создать новый std::unique_ptr для того же базового объекта.

1 голос
/ 11 апреля 2019

Перемещение объекта из набора

Вы можете использовать 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 из функции без удаления объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...