2

以下の結果は非常に興味深いもので、理解に苦慮しています。基本的に、intを持つクラスがあります:

class TestClass{
public:
    int test;
    TestClass() { test = 0; };
    TestClass(int _test) { test = _test; };
    ~TestClass() { /*do nothing*/ };
};

TestClass のポインタを受け取るテスト関数

void testFunction1(TestClass *ref){
    delete ref;
    TestClass *locTest = new TestClass();
    ref = locTest;
    ref->test = 2;
    cout << "test in testFunction1: " << ref->test << endl;
}

これは私が主にやっていることです:

int main(int argc, _TCHAR* argv[])
{
    TestClass *testObj = new TestClass(1);
    cout << "test before: " << testObj->test << endl;
    testFunction1(testObj);
    cout << "test after: " << testObj->test << endl;
    return 0;
}

私は出力が次のようになることを期待していました:

test before: 1
test in testFunction1: 2
test after: 1

しかし、次の出力が得られます。

test before: 1
test in testFunction1: 2
test after: 2

誰かがこれを説明できますか。興味深いのは、testFunction1 を次のように変更することです。

void testFunction1(TestClass *ref){
    //delete ref;
    TestClass *locTest = new TestClass();
    ref = locTest;
    ref->test = 2;
    cout << "test in testFunction1: " << ref->test << endl;
}

つまり、新しい場所を指す前に ref を削除しないと、次の出力が得られます。

test before: 1
test in testFunction1: 2
test after: 1

誰かが私にこの奇妙な振る舞いを説明してくれたら本当にありがたい. ありがとう。

4

6 に答える 6

4

のオブジェクトへのポインターのコピーを取得するtestFunction1()ため、それに代入しても、のポインターの元の値はmain()変更されません。

また、元のポインタ (in ) が指しているオブジェクトを ( in を呼び出すことによって) 削除していますが、 in の値がdelete更新されていないため、無効なオブジェクトにアクセスしています。に設定されている , は偶然であり、信頼することはできませんtestFunction1()main()main()testFunction1()

2 番目のケース ( を呼び出さない場合) で元の値を正しく読み取るという事実はdelete、元のオブジェクトが変更されていないためです (で新しいオブジェクトを変更し、testFinction1それへのポインターmainは同じです (上記で説明したように) )そしてオブジェクトはまだ生きている

于 2012-05-22T16:50:58.627 に答える
4

削除後にオブジェクトにアクセスした場合の動作は未定義です。

表示される動作は、システムのメモリ割り当てアルゴリズムに従います。

つまり、最初の testclass オブジェクトを削除した後、新しいオブジェクトにメモリを割り当てます。ランタイムは単にメモリを再利用します。

何が起こっているかを確認するには、ポインターの値を出力します。

void testFunction1(TestClass *ref){
    cout << ref << endl;
    delete ref;
    TestClass *locTest = new TestClass();
    cout << locTest << endl;
    ref = locTest;
    ref->test = 2;
    cout << "test in testFunction1: " << ref->test << endl;
}
于 2012-05-22T16:54:36.663 に答える
2

この場合、削除した古いオブジェクトと同じアドレスで新しいオブジェクトを取得しただけです。

実際には、testFunction1 を呼び出した後、testObj はダングリング ポインターになりました。

void testFunction1(TestClass *ref){
    delete ref;
    TestClass *locTest = new TestClass();
    cout << "locTest = " << locTest << endl;
    ref = locTest;
    ref->test = 2;
    cout << "test in testFunction1: " << ref->test << endl;
}

int main(int argc, char * argv[])
{
    TestClass *testObj = new TestClass(1);
    cout << "test before: " << testObj->test << endl;
    cout << "testObg = " << testObj << endl;
    testFunction1(testObj);
    cout << "test after: " << testObj->test << endl;
    cout << "testObg = " << testObj << endl;
    return 0;
}

出力は次のとおりです。

test before: 1
testObg = 0x511818
locTest = 0x511818
test in testFunction1: 2
test after: 2
testObg = 0x511818
于 2012-05-22T17:54:35.747 に答える
1

この指示の後:

TestClass *testObj = new TestClass(1);

オブジェクトを含む新しいメモリ領域を割り当てましたTestClass。そのアドレス ( と呼びましょうmaddr) は に格納されtestObjます。

さて、この命令:

cout << "test before: " << testObj->test << endl;

予想通り、出力1します。

内部には、値を含むポインターであるtestFunction1()というローカル変数があります。refmaddr

の場合、アドレスが であるオブジェクトdelete refを含むメモリ領域の割り当てを解除します。TestClassmaddr

次に、新しいメモリ領域を割り当てます。

TestClass *locTest = new TestClass();

locTestそのアドレスが含まれています。それを と呼びましょうm1addr

次にref、 でメモリ領域にアクセスし、値を にm1addr変更します。int test2

この命令:

cout << "test in testFunction1: " << ref->test << endl;

2期待通りの出力。

に戻ると、アドレスが であるオブジェクトをmain含む領域へのハンドラが失われ(つまり、メモリ リークが発生しています)、 が指す領域は割り当てられていません。TestClassm1addrtestObj

再度使用するtestObjと、消去された から始まるメモリ領域にアクセスしますmaddr。アクセスの効果testObj->testは、未定義の動作です。

あなたが経験したことは、コードを実行したときにmaddr == m1addr発生する可能性がありますが、これは偶然にのみ発生する可能性があり、これに依存することはできません.

于 2012-05-22T17:28:48.510 に答える
0

オッズは、古い削除されたオブジェクト(1)があった場所に新しいオブジェクト(2)が作成されていることです。元のポインタはまだその場所を指しているので、それにアクセスすると、誤って新しいオブジェクトにアクセスします(2を使用)。

于 2012-05-22T17:00:24.170 に答える
0

testFunction1 へのパラメーターの TestClass *ref と main の TestClass *testObj は、同じものへの 2 つの異なるポインターですが、同じポインターではありません。関数/メソッド内のオブジェクトを削除して再割り当てする場合は、ポインターへのポインターをパラメーターとして使用できます。

他の人が言及したように、testfunction1 の後、testfunction1 内で削除されたオブジェクトにアクセスしていますが、これも言及されているように未定義の動作です。ダングリング ポインターが指しているメモリは、削除中に解放されましたが、新しいへの別の呼び出し中にメモリの場所が再割り当てされるまで、コンテンツはまだそこにある可能性があります。したがって、いつでも簡単に上書きできる未割り当て領域を使用しています。

お役に立てれば

于 2012-05-22T17:35:36.177 に答える