0

メモリ リークのあるプログラムがあり、コードに削除を追加するたびにクラッシュします。なぜこれが起こっているのか、誰かが何か知っているかどうか疑問に思っています。クラッシュするコードは以下です。これは、ファーストネームとラストネームが次のように宣言されている削除を伴うデスタクタです。

char* firstName;
char* lastName;


Name::~Name(){

    delete[] firstName;
    delete[] lastName;
}

ここにメモリが割り当てられます

Name::Name(Name& name){
    //copys the first and last name from one Name to the other

    firstName = new char [strlen(name.firstName)+1];
    strcpy(firstName,name.firstName);

    lastName = new char [strlen(name.lastName)+1];
    strcpy(lastName,name.lastName);

}
4

2 に答える 2

1

ほとんどの場合、Nameある時点でタイプのオブジェクトを割り当てており、コピーの割り当てはありません (最初はコピー コンストラクターがないと思っていましたが、実際にはコピー コンストラクターを表示しています)。デフォルトの生成されたコピー割り当ては、ビットごとのコピーを行うだけです。その結果、delete[]ある時点で 2 倍のポインターが表示されます (メモリ リークもありますが、これはそれほど目立ちません)。または、他のコンストラクターはどのように見えますか? ポインターを初期化しないデフォルトのコンストラクターや、文字列リテラルへのポインターを格納する可能性のあるコンストラクターがありますか?

最良の方法は、手動のメモリ割り当てを使用するのではなくstd::string . std::stringたとえば、これが割り当てであるために を使用できない場合は、独自の単純な文字列クラスを実装することを強くお勧めします。割り当てられた複数のエンティティを、それぞれを適切なリソース維持クラスに個別にラップせずに処理することは非常に困難です。正しくできません。確かに、私は約 20 年間 C++ でしかプログラミングしていません。

たとえば、コピー コンストラクターは例外に対して安全ではありません。割り当てるメモリが不足しているために 2 番目の割り当てで例外がスローされた場合は、リソース リークが発生しています。関数レベルの try/catch ブロックを処理する方法はいくつかありますが、文字列クラスを使用する方がはるかに簡単です。コンストラクターが例外をスローすると、完全に構築されたサブオブジェクトはすべて自動的に破棄されます。このようにして、文字列のコンストラクターがメモリを処理します。

于 2013-11-09T22:46:41.320 に答える
0

と がクラスの適切な要素であると仮定するとfirstNamestrlen が NULL に対してチェックしないように注意する必要があるため、NULL を処理する必要があります。lastNameName

Name::Name(const Name& name){
    if (name.firstName) {
        int len_z = strlen(name.firstName)+1;
        firstName = new char [len_z];
        strncpy(firstName, name.firstName, len_z);
        // ^^^ also copy the terminator char ^^^
    } else {
        firstName = NULL;
    }
    // repeat for lastName:
    if (name.lastName) {
        int len_z = strlen(name.lastName)+1;
        lastName = new char [len_z];
        strncpy(lastName, name.lastName, len_z);

    } else {
        lastName = NULL;
    }
}

または、次のようなコンストラクターで標準Nameオブジェクトを作成します。

Name::Name() {
    firstName = new char[1];
    firstName[0] = '\0';
    // repeat for lastName:
    lastName = new char[1];
    lastName[0] = '\0';
}

少なくともここでは、なぜstd::stringがはるかに優れた選択であるかがわかります。これは、必要な文字列のすべての側面を実装するクラスです。これを手動で作成する場合、firstName と lastName のすべてを 2 倍にする必要があります...そして、クラスmiddleNameの次のバージョンにすぐに a があると想像してください...Name

于 2013-11-09T23:41:04.457 に答える