Как стереть элементы из boost :: ptr_vector

Поэтому я пытаюсь избавиться от моих std :: vector с помощью boost :: ptr_vector. Теперь я пытаюсь удалить элемент из одного, а также удалить удаленный элемент. Самым очевидным для меня было сделать:

class A
{ int m; };

boost::ptr_vector<A> vec;
A* a = new A;
vec.push_back(a);
vec.erase(a);

Но это даже не скомпилируется (полное сообщение об ошибке см. Ниже). Я попытался стереть / удалить идиому, как я бы это делал на std :: vector, но все алгоритмы boost :: ptr_vector оказываются немного отличными от таковых в std :: vector.

Итак, мои вопросы:

  • Как удалить указатель из ptr_vector?
  • Нужно ли мне вручную удалять () тот элемент, который я удалил?

Ошибка компилятора:

1>------ Build started: Project: ptr_vector_test, Configuration: Debug Win32 ------
1>Compiling...
1>ptr_vector_test.cpp
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2825: 'C': must be a class or namespace when followed by '::'
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\mpl\eval_if.hpp(63) : see reference to class template instantiation 'boost::range_const_iterator<C>' being compiled
1>        with
1>        [
1>            C=A *
1>        ]
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\range\iterator.hpp(63) : see reference to class template instantiation 'boost::mpl::eval_if_c<C,F1,F2>' being compiled
1>        with
1>        [
1>            C=true,
1>            F1=boost::range_const_iterator<A *>,
1>            F2=boost::range_mutable_iterator<A *const >
1>        ]
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\ptr_container\detail\reversible_ptr_container.hpp(506) : see reference to class template instantiation 'boost::range_iterator<C>' being compiled
1>        with
1>        [
1>            C=A *const 
1>        ]
1>        c:\tmp\ptr_vector_test\ptr_vector_test.cpp(21) : see reference to function template instantiation 'boost::void_ptr_iterator<VoidIter,T> boost::ptr_container_detail::reversible_ptr_container<Config,CloneAllocator>::erase<A*>(const Range &)' being compiled
1>        with
1>        [
1>            VoidIter=std::_Vector_iterator<void *,std::allocator<void *>>,
1>            T=A,
1>            Config=boost::ptr_container_detail::sequence_config<A,std::vector<void *,std::allocator<void *>>>,
1>            CloneAllocator=boost::heap_clone_allocator,
1>            Range=A *
1>        ]
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2039: 'const_iterator' : is not a member of '`global namespace''
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2146: syntax error : missing ';' before identifier 'type'
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2208: 'boost::type' : no members defined using this type
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : fatal error C1903: unable to recover from previous error(s); stopping compilation
1>Build log was saved at "file://c:\tmp\ptr_vector_test\Debug\BuildLog.htm"
1>ptr_vector_test - 5 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
10.12.2008 13:17:39
6 ОТВЕТОВ
РЕШЕНИЕ

Ну, вы можете сделать это с помощью std :: vector.

В обоих случаях стирание принимает итератор в качестве параметра.
Поэтому, прежде чем вы сможете что-то стереть из вектора (или ptr_vector), вам нужно найти его.

Также обратите внимание, что ptr_vector обрабатывает свое содержимое так, как будто вы сохранили объект, а не указатель. Таким образом, любой поиск осуществляется через объект.

Так в основном

 std::vector<A>       x;
 std::ptr_vector<A>   y;

 // These two object should behave in exactly the same way.
 // The ONLY difference is inserting values which for y are pointers.
 // Y take ownership of the pointer and all subsequent acesses to the
 // members of y look like they are objects

Пример:

#include <boost/ptr_container/ptr_vector.hpp>
#include <vector>

class A
{ int m;
    public:
    A(int x):m(x)   {}
    bool operator==(A const& rhs)   {return m = rhs.m;}
};

int main()
{
    boost::ptr_vector<A>    x;
    x.push_back(new A(1));
    x.erase(std::find(x.begin(),x.end(),A(1)));


    std::vector<A>          y;
    y.push_back(A(2));
    y.erase(std::find(y.begin(),y.end(),A(2)));

    // To find an exact pointer don't modify the equality.
    // Use find_if and pass a predicate that tests for a pointer
    A* a = new A(3);
    boost:ptr_Vector<A>     z;
    z.push_back(a);
    z.erase(std::find_if(y.begin(),y.end(),CheckPointerValue(a));
}

struct CheckPointerValue
{
     CheckPointerValue(A* a):anA(a) {}
     bool operator()(A const& x)    { return &X == anA;}
     private:
        A* anA;
};
9
11.12.2008 17:25:43
Я думаю, что вы были правы относительно моего ответа ниже. если я правильно понимаю, распределитель по умолчанию (heap_clone_allocator) сам клонирует объекты при перераспределении). хотя это бы сработало, если бы использовать view_clone_allocator. Я удалил свой ответ и проголосовал против тебя. веселиться :)
Johannes Schaub - litb 10.12.2008 18:43:18
Спасибо, моя проблема заключалась в том, что я не определил оператор == для A * const &, который представляется необходимым. Чтобы ваш пример компилировался (VC9), мне пришлось изменить «A const & rhs» на «A * const & rhs» и соответственно изменить содержимое тела. Это затрудняет использование библиотечных классов.
Roel 11.12.2008 12:46:10
Вы упускаете суть! Ptr_vector <> сохраняет объект как объект. Вместо того, чтобы извращать оператор равенства, просто отмените указатель. Если вы хотите найти точный указатель, вам нужно использовать find_if и передать предикат.
Martin York 11.12.2008 17:19:10

Вы можете использовать шаблонный метод erase_if.

vec.erase_if( predicate() );
1
10.12.2008 13:22:16
Но тогда мне нужно написать предикат специального назначения, который в основном является простым объектом функции сравнения? Какой беспорядок, если я так и буду работать с ptr_vector, я просто буду придерживаться своего вектора shared_ptr: /
Roel 10.12.2008 13:32:27
Используйте boost :: lambda, чтобы написать предикат как лямбда-функцию (на месте).
paxos1977 10.12.2008 15:02:37

Я думаю, что вы хотите вызвать .release () для вектора вместо стирания. Это удаляет запись и удаляет память.

См. Раздел «Новые функции» для получения подробной информации в руководстве или проверьте ссылку .

В качестве альтернативы, вам нужно получить итератор для элемента, чтобы вызвать erase (), я уверен, что A * считает в терминах ptr_vector.

3
10.12.2008 13:29:50
Нет - releaseудаляет указатель из контейнера, и контейнер сжимается, но объект не удаляется. У него та же семантика, что и у auto_ptr releaseвас - вы просто используете его для передачи управления.
EML 26.01.2012 22:00:34

Вам нужно использовать метод члена erase_if с подходящим предикатом. Удалить указатель не нужно, контейнер принадлежит.

struct delete_a {
    bool operator()(boost::ptr_vector<A>::value_type inA) {
       return inA == a;
    }
}

vec.erase_if(delete_a());

(обратите внимание, что это просто пример, выбранный для простоты, для такой ситуации в реальном коде, я полагаю, можно написать подходящую комбинацию bind / equal_to или использовать лямбду)

Или, в качестве альтернативы, вызовите release для правильного итератора, если вы все еще хотите использовать объект.

0
10.12.2008 13:33:09

Семантика ptr_vectorочень похожа на обычную vector. Вы должны найти элемент, прежде чем сможете его стереть.

1
10.12.2008 14:11:05
Да, стирание занимает итератор, ptr_vector ничем не отличается.
Greg Rogers 10.12.2008 14:33:39
Как мне найти вещи в ptr_vector? boost :: ptr_vector <A> :: iterator it = std :: find (vec.begin (), vec.end (), a); не работает (ошибка C2678: двоичный файл «==»: не найден оператор, который принимает левый операнд типа «A» (или нет приемлемого преобразования)).
Roel 10.12.2008 14:58:30
Я предполагаю, что мне нужен ptr_iterator, но он, кажется, защищен (хотя я мог найти сообщения в списках рассылки, где он использовался, так что я думаю, что он был сделан защищенным позже ...).
Roel 10.12.2008 14:59:16

Любопытная вещь: STL :: vector <> - это контейнер произвольного доступа , то есть он использует итераторы произвольного доступа .

Поэтому vec.erase (vec.begin () + N) удалит элемент с индексом N.

Обратите внимание, что это нарушает весь мем итератора, и вы больше не можете тривиально переключаться между векторами и списками ...

1
11.12.2008 23:29:18