У меня есть boost :: ptr_vector, содержащий указатели на класс «holdable».
boost::ptr_vector<holdable> items;
Я добавляю новые элементы в этот вектор из удерживаемого класса следующим образом:
currentplanet->items.push_back(this);
где currentplanet — указатель на объект класса, содержащего ptr_vector. Это все хорошо.
Что меня смущает, так это как удалить запись из ptr_vector из функции в своем собственном классе. Я пытаюсь:
currentplanet->items.erase(std::find(currentplanet->items.begin(),
currentplanet->items.end(),
this));
как в соответствии с ответом на аналогичный вопрос здесь: Как стереть элементы из boost :: ptr_vector, но я явно где-то ошибся, вероятно, в отношении использования «этого».
При попытке компиляции я получаю сообщение об ошибке от stl_algo.h
stl_algo.h|174|error: no match for 'operator==' in '__first.boost::void_ptr_iterator<VoidIter, T>::operator*
[with VoidIter = __gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*> > >,
T = holdable]() == __val'|
Я уверен, что это что-то очевидное, но меня, вероятно, смущает косвенность ptr_vector … спасибо за любые ответы заранее!
Как написали другие — это правда, что ptr_vector
вступает во владение вашим объектом, но если вы настаиваете на возможности удаления объекта из ptr_vector
само по себе — используйте find_if, а не find:
Holdable* ptr = this;
currentplanet->items.erase(std::find_if(currentplanet->items.begin(),
currentplanet->items.end(),
[ptr](const Holdable& other)
{return ptr == &other;} ));
Обратите внимание, что find
используется с *this
может найти другой объект, который равен *this
…
Для компиляторов, все еще не поддерживающих лямбда-выражения (эта вещь начинается с [ptr]
), используйте свой собственный предикат:
struct CompareToPtr {
CompareToPtr(Holdable* ptr) : ptr(ptr) {}
bool operator () (const Holdable& other) const { return &other == ptr; }
Holdable* ptr;
};
currentplanet->items.erase(std::find_if(currentplanet->items.begin(),
currentplanet->items.end(),
CompareToPtr(this)));
Я понял, что std :: find требует значения (не указателя) для третьего параметра, поэтому вы передаете диапазон [«begin», «end») для поиска и значение, которое вы ищете
Это то, что вы имели в виду?
currentplanet->items.erase(std::find(currentplanet->items.begin(),
currentplanet->items.end(),
*this));
обратите внимание на * это
Альф правильно, но по причине, которая несколько свойственна boost::ptr_vector
(и другие связанные boost::reversible_ptr_container
контейнеры), который я думаю, должен быть вызван. Обычно итератор элемента контейнера разыменовывает ссылку на контейнер value_type
,
boost:ptr_vector<T>::value_type
является typedef для T*
; Однако разыменование boost::ptr_vector<T>::iterator
не приводит к T*
ссылка.
Из ускоренной документации (http://www.boost.org/doc/libs/1_52_0/libs/ptr_container/doc/reversible_ptr_container.html):
Также обратите внимание, что
typedef ... iterator
позволяет перебирать T& объекты, а не Т *.
Разыменование boost::ptr_vector<T>::iterator
приводит к T&
, Вот почему вас смущает косвенность ptr_vector, и именно поэтому последний аргумент std::find()
должен быть holdable
объект, а не holdable*
,
Наконец, обратите внимание, что комментарий Xeo о ptr_vector
следует понимать владение указателями — это может иметь смысл в очень ограниченных ситуациях, когда объект хочет удалить себя, но вы должны делать это с полным пониманием того, что после этого erase()
звоните, вы ничего не можете сделать с объектом. Если это не то поведение, которое вам нужно, вместо erase()
Вы можете рассмотреть возможность использования release()
, который освободит контейнер от владения указателем и удалит его из контейнера (чтобы объект не был уничтожен).