0

STL ベクター内のオブジェクトを解放する次の例があります。

#include <map>
#include <string>


using namespace std;

class Test
{
   public:
      char*  name;
      int id;
      Test(char* n, int i);
};

Test::Test(char* n, int i)
{
   name = n;
   id = i;
}


int main ()
{
        Test* t = new Test("hi", 5);

        vector<Test> v;
        v.insert(v.end(), *t);

        for(vector<Test>::iterator it = v.begin(); it != v.end(); it++)
        {
                if (it->id == 5)
                {
                        Test* ptr = &*it;
                        v.erase(it);
                        delete ptr;
                        break;
                }
        }

        return 0;
}

私が調査してきたことによると、これはこれを行う正しい方法です。ただし、valgrind には次のような不満があります。

==7404== Invalid free() / delete / delete[]
==7404==    at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==7404==    by 0x400FD2: __gnu_cxx::new_allocator<Test>::deallocate(Test*, unsigned long) (new_allocator.h:94)
==7404==    by 0x401004: std::_Vector_base<Test, std::allocator<Test> >::_M_deallocate(Test*, unsigned long) (stl_vector.h:133)
==7404==    by 0x401045: std::_Vector_base<Test, std::allocator<Test> >::~_Vector_base() (stl_vector.h:119)
==7404==    by 0x40109C: std::vector<Test, std::allocator<Test> >::~vector() (stl_vector.h:272)
==7404==    by 0x400998: main (test.cc:46)
==7404==  Address 0x4C58070 is 0 bytes inside a block of size 16 free'd
==7404==    at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==7404==    by 0x40098A: main (test.cc:41)

そして、メモリリークがあります。これを行う正しい方法は何ですか?

4

4 に答える 4

4

いつもと同じ古いルールだ

every にnewは 1 つだけを付ける必要がありますdelete

あなたの場合、あなたが呼び出すnewのはのインスタンスを割り当てることだけですTest(そして、なぜそれをしているのかはまったく明らかではありませんが、それを無視しましょう)。次に、そのオブジェクトのコピーvectorを;に挿入します。挿入されたオブジェクトにメモリを割り当てていません。したがってdelete、 によって管理されるメモリを呼び出す必要はありませんvector

一方、delete割り当てたメモリを呼び出したことがないため、メモリリークが発生しています。を追加

delete t;

使い終わった後のコードのどこかにt


現在、ベクターがvector<Test *>代わりに宣言されている場合は、要素をベクターから削除する前に手動deleteで要素を削除する必要があります。ただし、ポインターのベクトルが必要な場合は、常にvector<unique_ptr<Test>>(または他のスマートポインター、またはboost::ptr_vector) を使用する必要があります。その場合、手動呼び出しはdelete必要ありません。

于 2013-07-25T22:12:36.217 に答える
4

Test* t = new Test("こんにちは", 5);

このオブジェクトをリークしています。オブジェクトのコピーを に保存してvectorいますが、後で元のオブジェクトを解放していません。

v.insert(v.end(), *t);

v.push_back(*t)代わりに使用してください。

if (それ->id == 5);

セミコロンが間違っています。削除する必要があります。

Test* ptr = &*it; v.erase(それ); ptr を削除します。

erase()問題ありませんが、deleteそうではありません。で割り当てられたオブジェクトを に保存してnewいないため、それらをまったくvector試してはいけません。delete所有していないメモリを解放しようとしています。

そうは言っても、選択肢は 2 つあります。

  1. ポインタを次の場所に格納しますvector

    int main ()
    {
        Test* t = new Test("hi", 5);
    
        vector<Test*> v;
        v.push_back(t);
    
        for(vector<Test*>::iterator it = v.begin(); it != v.end(); ++it)
        {
            Test* ptr = *it;
            if (ptr->id == 5)
            {
                v.erase(it);
                delete ptr;
                break;
            }
        }
    
        return 0;
    }
    
  2. ベクトルにポインターを格納しないでください。

    int main ()
    {
        /*
        Test *t = new Test("hi", 5);
    
        vector<Test> v;
        v.push_back(*t);
    
        delete t; // don't forget this!
        */
    
        vector<Test> v;
        v.push_back(Test("hi", 5));
    
        for(vector<Test>::iterator it = v.begin(); it != v.end(); ++it)
        {
            if (it->id == 5)
            {
                v.erase(it);
                break;
            }
        }
    
        return 0;
    }
    

std::find_if()参考までに、手動ループの代わりに使用することを検討してください。

struct IsId
{
    int _id;
    IsId(int id) : _id(id) {}
    bool operator()(const Test &src) const { return (src.id == _id); }
};

vector<Test>::iterator it = find_if(v.begin(), v.end(), IsId(5));
if (it != v.end())
{
    v.erase(it);
}
于 2013-07-25T22:16:43.037 に答える
2

まともな C++ でコードを記述する正しい方法は次のようになります。

int main()
{
    std::vector<Test> v { Test(""hi", 5) };

}   // returns 0, frees all allocated resources
于 2013-07-25T22:23:24.120 に答える
2

ベクトル::消去:

ベクトルから単一の要素 (位置) または要素の範囲 ([first,last)) を削除します。

これにより、破棄される削除された要素の数だけ、コンテナーのサイズが効果的に縮小されます。

したがって、消去機能を使用するだけです。ポインターを使用して削除する必要はありません。

新しいインスタンスを vector に挿入するときは、次の点に注意してください。

v.insert(v.end(), *t);

クラスは vector で再度コピー構築されるため、 に 1 つと に 1 つの 2 つの別個のインスタンスが残りtますv[0]

于 2013-07-25T22:10:51.683 に答える