1

ここでノブ。本から演習を行っていますが、コンパイラはエラーを報告しませんが、実行しようとするとプログラムがクラッシュします。

Cow クラスのさまざまなメソッドを実行する小さなプログラムを実行しようとしています。コンストラクタ、デフォルト コンストラクタ、コピー コンストラクタ、デストラクタ、オーバーロードされた代入演算子、およびその内容を表示するメソッドを明示的に持っています。

プロジェクト全体を配置します。

クラス仕様:

//cow.h -- For project Exercise 12.1.cbp

class Cow
{
    char name[20]; // memory is allocated in the stack
    char *hobby;
    double weight;
public:
    Cow();
    Cow(const char *nm, const char *ho, double wt);
    Cow(const Cow &c);
    ~Cow();
    Cow & operator=(const Cow &c);
    void ShowCow() const; // display all cow data
};

メソッドの実装:

// cow.cpp -- Cow class methods implementation (compile with main.cpp)

#include <cstring>
#include <iostream>
#include "cow.h"

Cow::Cow() // default destructor
{
    strcpy(name, "empty");
    hobby = new char[6]; // makes it compatible with delete[]
    strcpy(hobby, "empty");
    weight = 0.0;
}

Cow::Cow(const char *nm, const char *ho, double wt)
{
    strcpy(name, nm); // name = nm; is wrong, it copies the address of the argument pointer (swallow copying)
    /*if (name[20] != '\0') // if it's not a string, make it a string (in case nm is larger than 20)
        name[20] = '\0';*/
    hobby = new char[strlen(ho) + 1]; // allocates the needed memory to hold the argument string
    strcpy(hobby, ho); // copies the pointed-to data from the argument pointer to the class pointer
    weight = wt;
}

Cow::Cow(const Cow &c) // copy constructor
{
    strcpy(name, c.name); // copies the value to the desired address
    char *temp = hobby; // stores the address of the memory previously allocated with new
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby); // copies the value to the new address
    delete[] temp; // deletes the previously new allocated memory
    weight = c.weight;
}

Cow::~Cow()
{
    delete[] hobby;
}

Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
    strcpy(name, c.name);
    char *temp = hobby;
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby);
    delete[] temp;
    weight = c.weight;
    return *this;
}

void Cow::ShowCow() const
{
    std::cout << "Name: " << name << '\n';
    std::cout << "Hobby: " << hobby << '\n';
    std::cout << "Weight: " << weight << "\n\n";
}

クライアント:

// main.cpp -- Exercising the Cow class (compile with cow.cpp)

#include "cow.h"
#include <iostream>

int main()
{
    using std::cout;
    using std::cin;

    Cow subject1; // default constructor
    Cow subject2("Maria", "Reading", 120); // non-default constructor
    Cow subject3("Lula", "Cinema", 135);
    subject1 = subject3; // overloaded assignment operator
    Cow subject4 = subject2; // copy constructor
    subject1.ShowCow();
    subject2.ShowCow();
    subject3.ShowCow();
    subject4.ShowCow();

    cin.get();
    return 0;
}

考えられる問題を特定するためにコードの一部を隠していましたが、プログラムは次の 2 行が気に入らないようです。

subject1 = subject3;
Cow subject4 = subject2

特に、オーバーロードされた代入演算子とコピー コンストラクターでは、delete[] temp行を非表示にしても、プログラムはクラッシュしません。

私はまったくの初心者で、おそらく何かばかですが、これらの定義で何が間違っているのかわかりません。

何か助けはありますか?

4

2 に答える 2

3
Cow::Cow(const Cow &c) // copy constructor
{
    strcpy(name, c.name); // copies the value to the desired address
    char *temp = hobby; // stores the address of the memory previously allocated with new
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby); // copies the value to the new address
    delete[] temp; // deletes the previously new allocated memory
    weight = c.weight;
}

コピーC-TORです。以前に割り当てられたメンバーはありません。this->hobbyランダムなガベージを指します。したがって、あなたがdelete[] temp(つまりthis->hobby、新しい割り当ての前に)UBを取得します。

Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
    strcpy(name, c.name);
    char *temp = hobby;
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby);
    delete[] temp;
    hobby = name;
    weight = c.weight;
    return *this;
}

hobby = nameメモリリークが発生するため、正しくありません + デストラクタは、で割り当てられていないオブジェクトを削除しようとしoperator new[]ます。

于 2012-08-22T13:53:14.117 に答える
0

@ForEveR コピー コンストラクターが、割り当てられていないメモリを削除していることに既に注意しました。

しかし、演習全体に欠陥があり、C++ ではなくクラスで C を教えていると主張します。文字列を使用すると、リソースを直接管理する必要がないため、すべての問題が解消されます。これにより、デストラクタを記述したり、代入/コンストラクタを完全にコピーしたりする必要がなくなります。例えば:

class Cow
{
    std::string name;
    std::string hobby;
    double weight;
public:
    Cow();
    Cow(const std::string& nm, const std::string& ho, double wt);
    void ShowCow() const; // display all cow data
};
于 2012-08-22T14:05:33.620 に答える