web-dev-qa-db-ja.com

オブジェクトポインターのベクトルのvector :: erase()はオブジェクト自体を破壊しますか?

オブジェクトへのポインターのベクトルがあります。ベクターから要素を削除し、その要素を別のリストに配置する必要があります。

私は、ベクトルからオブジェクトを削除するために消去を使用できることを読みましたが、そうする前にオブジェクトデストラクタを呼び出すことも読みました。

オブジェクトを消去してもオブジェクトが破壊されるかどうかを知る必要があります。

39
cesar

vector::erase
ベクターコンテナから削除し、デストラクタを呼び出しますが、含まれるオブジェクトがポインタである場合、それを破壊する所有権を取得しません。

含まれている各ポインターで明示的にdeleteを呼び出して、ポインターが指しているコンテンツを削除する必要があります。次に例を示します。

void clearVectorContents( std::vector <YourClass*> & a ) 
{    
    for ( int i = 0; i < a.size(); i++ ) 
    {       
        delete a[i];    
    }    
    a.clear(); 
} 

生のポインタを標準コンテナに保存することはお勧めできません。 newによって割り当てられる必要があるリソースを保存する必要がある場合は、boost::shared_ptrを使用する必要があります。 Boost documentation をご覧ください。

より一般的でエレガントなソリューション:
このソリューションは、コメントで@Billyが指摘したように、for_eachおよびtemplatesを使用します。

// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};

そして、これは次のように呼び出すことができます:

for_each( myclassVector.begin(),myclassVector.end(),
          DeleteVector<myclass*>());

ここで、myclassVectormyclassクラスオブジェクトへのポインターを含むベクトルです。

使用例:

#include "functional"
#include "vector"
#include "algorithm"
#include "iostream"

//Your class
class myclass
{
    public:
        int i;
        myclass():i(10){}
};


// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};


int main()
{
    // Add 10 objects to the vector.
    std::vector<myclass*> myclassVector;

    for( int Index = 0; Index < 10; ++Index )
    {
        myclassVector.Push_back( new myclass);
    }

    for (int i=0; i<myclassVector.size(); i++) 
    {
        std::cout << " " << (myclassVector[i])->i;
    }

    // Now delete the vector contents in a single  line.
    for_each( myclassVector.begin(),
              myclassVector.end(),
              DeleteVector<myclass*>());

    //Clear the vector 
    myclassVector.clear();

    std::cout<<"\n"<<myclassVector.size();

    return 0;
}
59
Alok Save
  • vector<MyObject>がある場合、MyObject::~MyObjectが呼び出されます。
  • vector<MyObject*>がある場合、delete <MyObject instance>は呼び出されません。

2つのベクター間でMyObjectを移動するには、まず目的のベクターに挿入してから、元のベクターを消去する必要があります。これにより、オブジェクトの新しいコピーが作成されることに注意してください。ポインターを移動するときは、ポインターを一時変数に保持し、ベクターから消去してから、必要な場所に挿入するだけです。

そして、ベクター内のすべてのアイテムを削除してから削除する別の簡単な方法を次に示します。

template<class T> void purge( std::vector<T> & v ) {
    for ( auto item : v ) delete item;
    v.clear();
}
9
Tomas Andrle

はい、もちろんそうです。オブジェクトがベクターに存在しない場合、他にどこに存在しますか?

編集:これはnotポインターが指すものをすべて削除します。オブジェクトのライフタイムを管理するには、shared_ptrなどの自動ライフタイム管理ポインターを使用する必要があります。

2
Puppy

はい、eraseは要素を破壊します。ただし、要素を別のコンテナに配置する場合は、おそらくコピーを作成して他のコンテナに配置します。問題が発生する唯一の方法は、ポインターまたはそのようなものを他のコンテナーにコピーした場合です。

2
Billy ONeal

はい。 vector::eraseは、デストラクタの呼び出しを伴う削除されたオブジェクトを破棄します。

2
Dominic Gurto