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

您获得了指向 in 对象的指针的副本testFunction1(),因此当您分配给它时,指针 in 的原始值main()不会改变

此外,您正在删除原始指针 (in ) 指向的对象 (通过调用deletein ),但由于 in 的值未更新,您正在访问一个无效的对象 - 事实上您可以读取您的值入, 纯属巧合, 不可信赖testFunction1()main()main()testFunction1()

您在第二种情况下正确读取原始值(当您不调用时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

在这种情况下,您刚刚获得的新对象与您删除的旧对象位于同一地址。

实际上 testObj 在你调用 testFunction1 之后变成了一个悬空指针。

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()有一个名为 的局部变量ref,它是一个包含值的指针maddr

当你delete ref,你释放包含一个TestClass对象的内存区域,其地址是maddr

然后分配一个新的内存区域:

TestClass *locTest = new TestClass();

locTest包含它的地址,我们称之为m1addr

然后您使用ref访问内存区域m1addr并将int test值更改为2

该指令:

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

2按预期输出。

现在,回到main,您已经丢失了包含TestClass地址为的对象的区域的任何处理程序(即,您正在泄漏内存)并且不再分配m1addr指向的区域。testObj

当您testObj再次使用时,您将访问从 开始的内存区域,maddr该区域已被清除。访问的效果testObj->test是未定义的行为。

你所经历的可能是当你运行你的代码时maddr == m1addr,但这只能偶然发生,你不能依赖它。

于 2012-05-22T17:28:48.510 回答
0

奇怪的是,新对象(带有 2)正在创建的旧对象(带有 1)曾经是。您的原始指针仍指向该位置,因此当您访问它时,您会意外访问新对象(带有 2)。

于 2012-05-22T17:00:24.170 回答
0

testFunction1 参数中的 TestClass *ref 和 main 中的 TestClass *testObj 是指向同一事物的 2 个不同指针,但它们不是同一个指针。如果要在函数/方法中删除和重新分配对象,可以使用指向指针的指针作为参数。

正如其他人所提到的,在 testfunction1 之后,您正在访问一个在 testfunction1 中被删除的对象,这也提到了未定义的行为。悬空指针指向的内存在删除期间被释放,但内容可能仍然存在,直到在另一个调用 new 期间重新分配内存位置。因此,您正在使用随时可以很容易地覆盖的未分配空间。

希望这可以帮助

于 2012-05-22T17:35:36.177 回答