2

構造体へのポインターの配列を実装するクラスを作成しました...この配列にレコードを追加する方法は知っていますが、それらを適切に削除する方法がわからないため、メモリリークが発生しました。必要に応じて配列のサイズが大きくなり、配列のサイズとそこにいくつのレコードがあるかがわかります。私は、ガベージ コレクターを備えた言語でのコーディングに慣れているため、これはかなり混乱します。その配列を適切に解放する方法を教えていただければ幸いです。

Plsは、私が使用できないことに注意してくださいvector。私はそれらに限定されています:

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>

私のコード:

struct DbRecord
{
    string oName;
    string oAddr;
    string cName;
    string cAddr;
};

class CCompanyIndex
{
    public: CCompanyIndex(void);~CCompanyIndex(void);
    bool Add(const string & oName,
    const string & oAddr,
    const string & cName,
    const string & cAddr);
    bool Del(const string & oName,
    const string & oAddr);
    bool Search(const string & oName,
    const string & oAddr,
    string & cName,
    string & cAddr) const;

    int size;
    int position;
    DbRecord * * db;
};

CCompanyIndex::CCompanyIndex(void)
{
    db = new DbRecord * [1000];

    size = 1000;
    position = 0;
}

CCompanyIndex::~CCompanyIndex(void)
{
}

int main(int argc, char const * argv[])
{

    CCompanyIndex c1;
    // do something..with c1, i.e. add there some records to array
    // ...
    // ...
    // delete it now
}
4

4 に答える 4

1

未加工のポインタ、 、およびを使用std::vectorしてメモリを手動で管理する必要がないようにするために使用します。そうすることは(あなたが経験したように)エラーが発生しやすく、メモリリークや未定義の動作に簡単につながります。new[]delete[]

DbRecordまた、まったく同じ理由で、オブジェクトへの参照を保持するために、生のポインターの代わりにスマート ポインターを使用することをお勧めします。目的の所有権ポリシーに従ってスマート ポインターを選択する必要があります。ここでは、std::shared_ptr適切であると仮定します。

ただし、参照セマンティクスが必要ない場合は、ポインターをまったく使用せず、std::vector<DbRecord>代わりにコンテナーを宣言する必要があることに注意してください。元のバージョンでは (生の) ポインターが使用されていたため、参照セマンティクスが必要であると仮定します。ただし、そうでない場合は、ポインターを使用しないでください。

したがって、必要な#includeディレクティブとusing宣言が与えられた場合:

#include <string>
#include <vector>
#include <memory>

using std::string;
using std::vector;
using std::shared_ptr;

そして、DbRecordデータ構造の(変更されていない)定義:

struct DbRecord {
    string oName;
    string oAddr;
    string cName;
    string cAddr;
};

この方法で定義を変更できますCCompanyIndex(ご覧のとおり、ユーザー定義のデフォルト コンストラクターとデストラクターは不要になり、コンパイラーにそれらを暗黙的に生成させることができます)。

class CCompanyIndex {
public:

//  No more need for a user-defined default constructor and destructor!

    bool Add(const string & oName,
            const string & oAddr,
            const string & cName,
            const string & cAddr);
    bool Del(const string & oName,
            const string & oAddr);
    bool Search(const string & oName,
            const string & oAddr,
            string & cName,
            string & cAddr) const;

    std::vector<std::shared_ptr<DbRecord>> db;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

最後に、手動でクリーンアップを実行する必要がないことに注意してください。

int main(int argc, char const *argv[])
{
    CCompanyIndex c1;
    // do something..with c1, i.e. add there some records to array
    // ...
    // ...

    // NO NEED TO MANUALLY DELETE IT NOW!
}
于 2013-03-31T13:28:38.470 に答える
1

経験則では、メモリ管理に関連するコンストラクターで行われる操作をデストラクタで逆にすることです。とはいえdb = new DbRecord * [1000];、コンストラクターにあるので、デストラクターに a が必要ですdelete[] db;

ただし、ここでは動的メモリ管理が必要ない可能性が高く (by value セマンティクスを使用)、C++ が提供するvectorクラスなどの高レベルの抽象化を調べたい場合があることに注意してください。

于 2013-03-31T13:36:01.777 に答える
0

ここでメモリ管理を行うべきではありません。array new を使用する理由はほとんどありません。そのまま使用して std::vectorください。DbRecordそして、あなたの;を動的に割り当てる理由は本当にありません。値のセマンティクスがあるため:

std::vector<DbRecord> db;

うまく仕事をします。

于 2013-03-31T13:31:34.880 に答える