2012-05-22 74 views
2

以下结果非常有趣,我很难理解它们。基本上我有它有一个int类:C++中指针的奇怪行为

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; 
} 

即我不把它指向新的位置之前删除裁判,我得到下面的输出:

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

我会很感激,如果有人可以给我解释一下这种奇怪的行为。谢谢。

+0

没有更改主 – umair

回答

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; 
} 
4

你得到的指针对象的副本testFunction1(),所以当你分配给它,在main()指针的原始值不会改变

此外,您可以通过调用delete删除对象(在testFunction1())原始指针(在main())指向,但由于main()中的值未更新,您正在访问一个无效的对象 - 事实上,您可以读取您在testFunction1()中设置的值,这是一个巧合并且不能依靠

事实上,您正确地读取原始值在第二种情况下(当您不调用delete时)是因为原始对象未被更改(您在testFinction1中更改了新的对象,并且main中的指针与它相同(如上所述),而对象是仍然活着

+0

究竟造的,内存泄漏是在testFunction1(),因为你难道没有拿到新创建的内存的地址外关闭功能。 – Brady

+0

但为什么主要指针的值从1更新为2,如果我们正在将一个副本传递给testFunction1() – umair

+3

@umair:这是未定义的行为。你没有任何期望的权利。 –

0

赔率是新的对象(2)旧删除的对象(1)用于对创建是。你的原始指针仍然指向那个位置,所以当你访问它时,你意外地访问了新的对象(用2)。

1

执行该指令后:

TestClass *testObj = new TestClass(1); 

您已经分配包含TestClass对象,其地址的新内存区(姑且称之为maddr)存入testObj

现在,这个指令:

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

输出1,符合市场预期。

Inside testFunction1()您有一个局部变量,称为ref,它是一个包含值maddr的指针。

当您使用delete ref时,将取消分配包含TestClass对象(其地址为maddr)的内存区域。

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

TestClass *locTest = new TestClass(); 

locTest包含其地址,让我们称之为m1addr

然后使用refm1addr访问内存区域和int test值更改为2

该指令:

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

输出2如预期。现在

,回main,你已经失去了任何处理程序包含TestClass对象,其地址为m1addr(也就是你正在泄漏内存)的面积和区域指向testObj不再被分配。

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

你所遇到的可能是这样的事实,即当你运行你的代码maddr == m1addr,但这只能偶然发生,你不能依靠这个。

0

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

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

希望这有助于

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