Перемещение умного указателя из одного unordered_set из другого

template<class T>
Class Node
{
    //irrelavant functs
};
class A
{
    unordered_set<unique_ptr<Node<T>>, myHash<Node<T>>, myEqual<Node<T>>> nodes
    shared_ptr<A> child;

    void moveToChild()
    {
        for(auto it = nodes.begin(); it < nodes.end(); ++it) {
            if (some_cond) {
                child->nodes.emplace(std::move(*it));
            }
        }
    }
};

У меня есть класс, который содержит кучу узлов в unordered_set и имеет указатель на себя, называемый дочерним. Когда выполняются некоторые произвольные условия, этот класс должен переместить некоторые (или все) свои указатели на объекты Node в контейнер дочерних узлов. Но я не уверен, возможно ли это, поскольку ключи в unordered_sets являются константами.

Я не возражаю против создания нового интеллектуального указателя, но я не могу позволить себе создавать новый узел каждый раз, когда я перемещаю его или удаляю из unordered_set. Если то, что я пытаюсь сделать, невозможно с unique_ptrs, мне интересно, возможно ли это с shared_ptrs?

Я никогда не реализовывал свои собственные распределители для контейнеров STL, поэтому не уверен, что я на правильном пути, но я думал о написании собственного распределителя для unordered_set, который принимает логическое значение, если это правда, он удаляет объект, если это ложь, это не так. не освобождает указатель, а удаляет его из контейнера (опять же, не уверен, что смогу сделать такое резкое изменение в поведении контейнера)

Итак, можно ли как-то переместить умный указатель из одного unordered_set в другой, не освобождая его?

Примечание. Пожалуйста, не обращайте внимания на опечатки и синтаксические ошибки, это сильно упрощенная версия моего кода.


person duoren    schedule 30.01.2015    source источник
comment
Вам нужно будет стереть элементы вектора из родительского списка, если вы переносите их в дочерний элемент.   -  person AndyG    schedule 31.01.2015
comment
@AndyG Я хочу создать временный shared_ptr и удалить исходный из набора, но я не уверен, смогу ли я сделать это, не освобождая объект, на который указывает интеллектуальный указатель.   -  person duoren    schedule 31.01.2015


Ответы (1)


Ваш код обманывает std::set, возвращая свои элементы только по постоянной ссылке, используя < на итераторах, не удаляя выпотрошенные элементы из std::unordered_set и некоторые незначительные опечатки.

void moveToChild() {
    for(auto it = nodes.begin(); it != nodes.end();)
        if (some_cond) {
            child->nodes.emplace(std::move(const_cast<nodes::reference>(*it)));
            // Must const_cast above because the set only gives constant access.
            it = nodes.erase(it); // Remove element
        } else
            ++it;
}
person Deduplicator    schedule 30.01.2015
comment
По крайней мере, для меня, на GCC 8.3.0, я получаю ошибку при попытке сделать это. Насколько я могу судить, erase(it) нужно, чтобы содержимое этого элемента было действительным, чтобы он мог сравнивать его с другими внутренними элементами и т. д. Но если кишки были std::move повреждены, он падает. В общем, небезопасно делать произвольные вещи с объектом после того, как он был перемещен, и я не знаю, дает ли erase какие-либо гарантии относительно того, что он может или не может делать под капотом. - person jwd; 10.02.2020