1

この問題は私を混乱させました。コードの最初の部分は、クラッシュすることなく正常に動作し、s1 を s2 に完全に正常に割り当てます。しかし、コードの 2 番目のグループは、プログラムをクラッシュさせます。

なぜこれが起こっているのか、何が問題なのか、誰にも分かりますか?

コード 1:(動作)

    s1.add(10, 30, 25, "Test Screen", false);
s1.add(13, 10, 5, "Name:XXX", false);
s1.add(13, 18, 30);
s1.remove(-1);
Screen s2 = s1;

コード 2:(割り当て時にクラッシュ)

    Screen s1;

    if (1 != s1.add(10, 30, 25, "Test Screen", false))
        message("first add() has a problem");
   else if (2 != s1.add(13, 10, 5, "Name:XXX", false))
        message("second add() has a problem");
    else if (3 != s1.add(13, 18, 30))
        message("third add() has a problem");
    else if (3 != s1.remove(-1))
       message("first remove() has a problem");
    else {
        Screen s2 = s1;
}

画面クラスの代入演算子:

        Screen& operator=(const Screen &scr) {
        if (this != &scr){
            for (int i = 0; i < 50; i++) {
                if  (fields[i])
                    delete fields[i];
                fields[i] = new LField();
            }

            for (int i = 0; i < scr.numOfFields; i++)
                fields[i] = scr.fields[i];

            numOfFields = scr.numOfFields;
            currentField = scr.currentField;
        }
        return *this;
    }

Field クラスの代入演算子:

LField& operator=(const LField &lfieldobj) {
        if (this != &lfieldobj) {

            if (lfieldobj.val) {
                if (val)
                    delete[] val;
                val = new char[strlen(lfieldobj.val) + 1];
                strcpy(val, lfieldobj.val);
            }
            else{
                //val = new char[1];
                val = "";
            }
            rowNum = lfieldobj.rowNum;
            colNum = lfieldobj.colNum;
            width = lfieldobj.width;
            canEdit = lfieldobj.canEdit;
            index = lfieldobj.index;

        }
        return *this;
    }

どんな入力でも大歓迎です:)

4

6 に答える 6

2

あなたの現在を取り除きvalstd::string. your を取り除き、fieldsに置き換えますstd::vector。これにより、オーバーロードされた代入演算子の両方を排除できるはずです。コンパイラは機能するものを提供します。コードとともにメモリ管理の問題を解消できると思います。

現状では、知っているメモリ管理の問題を「修正」したとしても、例外に直面するとコードが完全に安全ではないという事実が残ります (new基本的にはそのように使用します)。例外も回避できません)。

于 2010-06-21T14:29:59.593 に答える
2
        for (int i = 0; i < scr.numOfFields; i++)
            fields[i] = scr.fields[i];

大丈夫ではありません。ポイント先の値ではなくポインターをコピーしています。ディープ コピーが必要です。

于 2010-06-21T14:31:08.340 に答える
1

メンバーの「フィールド」宣言とは何ですか?

LField* fields[50]?

もしそうなら、左側のオブジェクト フィールド メンバーを に初期化しているのはNULL誰ですか? 私は誰とも言いません...代入演算子はC++のコピーコンストラクターのようなもので、無効なポインターで削除を呼び出しています。

于 2010-06-21T14:17:29.043 に答える
1

この線

Screen s2 = s1;

実際にはScreen、代入演算子のオーバーロードではなく、コピー コンストラクターを呼び出します。

例えば:

#include <iostream>
using namespace std;

class Screen
{
public:
        Screen() { }

        Screen(const Screen& s)
        {
                cout << "in `Screen::Screen(const Screen&)`" << endl;
        }

        Screen& operator=(const Screen& s)
        {
                cout << "in `Screen::operator=(const Screen&)`" << endl;
                return *this;
        }
};

int main()
{
        Screen s1;
        Screen s2 = s1;
}

プリント:

Screen::Screen(const Screen&)

あなたのScreenコピー コンストラクターは と同様に定義されていると推測してScreen::operator=(const Screen&)いるため、代入演算子のオーバーロードの修正をコピー コンストラクターの定義にも適用する必要があるかもしれません。

また、fieldsメンバーはどのようにScreen定義されていますか? 次のような場合:

LField* fields[50];

LField*次に、コンストラクター内で、配列内のすべてのオブジェクトを初期化する必要がありNULLます。初期値が未定義であるためです。

std::fill_n(fields, 50, static_cast<LField*>(NULL));

この初期化を行わないと、 が割り当てを指していなくても、テストif (fields[i])が成功する可能性があります。ifields[i]deletenew

于 2010-06-21T14:33:16.747 に答える
0

複雑なオブジェクトの場合は、copy and swap idum を使用することをお勧めします。
これにより、強力な例外保証 (トランザクション上安全) を持つ代入演算子が得られます。しかし、これは、1 つの場所 (コンストラクター) での複雑なオブジェクトの作成のみを考慮する必要があることも意味します。

Screen& Screen::operator=(Screen const& rhs)
{
    Screen tmp(rhs);
    this->swap(tmp);
    return *this;
}

void Screen::swap(Screen const& rhs) throw ()
{
     // Swap each of the members for this with rhs.
     // Use the same pattern for Field.
}
于 2010-06-21T15:02:48.703 に答える
0

私はそれを修正することができました。結局、メモリ割り当ての問題でした:)

于 2010-06-21T14:27:49.287 に答える