7

したがって、boost::ptr_vector を使用して std::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 からポインターを削除するにはどうすればよいですか?
  • 削除した要素を手動で delete() する必要はありますか?

コンパイラ エラー:

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 ==========
4

6 に答える 6

9

std::vector を使用してそれを行うこともできます。

どちらの場合も、erase はイテレータをパラメータとして受け取ります。
そのため、ベクター (または 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;
};
于 2008-12-10T18:18:58.783 に答える
3

消去の代わりにベクトルで .release() を呼び出したいと思います。これにより、エントリが削除され、メモリが削除されます。

詳細については、チュートリアルの「新しい関数」セクションを参照するか、リファレンスを確認してください。

または、erase() を呼び出すために要素への反復子を取得する必要があります。ptr_vector に関して A* がカウントされることは確かではありません。

于 2008-12-10T13:29:50.303 に答える
1

のセマンティクスはptr_vector、通常のと非常によく似ていvectorます。消去する前に、要素を見つける必要があります。

于 2008-12-10T14:11:05.523 に答える
1

erase_if テンプレート メソッドを使用できます。

vec.erase_if( predicate() );
于 2008-12-10T13:22:16.153 に答える
1

興味深いことに: STL::vector<>Random Access Containerです。つまり、Random Access Iteratorsを使用します。

したがって、vec.erase(vec.begin()+N)はインデックス N の要素を削除します。

そうすることでイテレータミーム全体が壊れ、ベクトルとリストを自明に切り替えることができなくなることに注意してください...

于 2008-12-11T23:29:18.720 に答える
0

適切な述語でメンバー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を呼び出します。

于 2008-12-10T13:33:09.750 に答える