简体   繁体   English

c ++中指针的奇怪行为

[英]Strange behavior of pointers in c++

Following results are very interesting and I am having difficulty understanding them. 以下结果非常有趣,我很难理解它们。 Basically I have a class which has an int: 基本上我有一个有int的类:

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

A test function which accepts a pointer of TestClass 一个测试函数,它接受TestClass的指针

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

This is what I am doing in main: 这就是我在主要做的事情:

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

I was expecting output to be: 我期待输出为:

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

But I get the following output: 但我得到以下输出:

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

Can someone explain this. 有人可以解释一下吗。 Interesting thing is that changing testFunction1 to: 有趣的是将testFunction1更改为:

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

ie I do not delete ref before pointing it to new location, I get the following output: 即我在将其指向新位置之前不删除ref,我得到以下输出:

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

I would really appreciate if someone can explain me this strange behavior. 如果有人能解释我这种奇怪的行为,我真的很感激。 Thanks. 谢谢。

You get a copy of the pointer to the object in testFunction1() , so when you assign to it, the original value of the pointer in main() does not change 你得到一个指向testFunction1()对象的指针的副本,所以当你赋值给它时, main()中指针的原始值不会改变

Also, you are deleting the object (by calling delete in testFunction1() ) to which the original pointer (in main() ) is pointing, but as the value in main() is not updated, you are accessing an invalid object -- the fact that you can read the value that you set in testFunction1() , is a coincidence and cannot be relied on 此外,您正在删除原始指针(在main() )指向的对象(通过调用testFunction1() delete ),但由于main()值未更新,您正在访问无效对象 -您可以读取您在testFunction1()设置的值这一事实是巧合,不能依赖于

The fact that you correctly read the original value in the second case (when you don't call delete ) is because the original object has not been changed (you change a new one in testFinction1 and the pointer to it in main is the same (as explained above) and the object is still alive 您在第二种情况下(当您不调用delete )正确读取原始值的事实是因为原始对象尚未更改(您在testFinction1更改了一个新的并且在main指向它的指针是相同的(如上所述)并且物体仍然存在

When you access the object after deleting it, the behaviour is undefined. 在删除对象后访问该对象时,行为未定义。

The behaviour that you see follows from the memory allocation algorithm in your system. 您看到的行为遵循系统中的内存分配算法。

That is after deleting your first testclass object, you allocate memory for a new object. 这是在删除第一个testclass对象之后,为新对象分配内存。 The runtime simply reuses the memory. 运行时只是重用内存。

To check what is going on, print the values of the pointers: 要检查发生了什么,请打印指针的值:

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

in this case , you just got the new object at the same address with the old one you delete. 在这种情况下,您只需将新对象与您删除的旧对象放在同一地址。

actually testObj became a dangling pointer after you call testFunction1. 实际上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;
}

Output is : 输出是:

test before: 1
testObg = 0x511818
locTest = 0x511818
test in testFunction1: 2
test after: 2
testObg = 0x511818

After this instruction: 在这个指示之后:

TestClass *testObj = new TestClass(1);

you have allocated a new memory area containing a TestClass object, whose address (let's call it maddr ) is stored into testObj . 你已经分配了一个包含TestClass对象的新内存区域,其地址(让我们称之为maddr )存储在testObj

Now, this instruction: 现在,这条指令:

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

outputs 1 , as expected. 输出1 ,如预期的那样。

Inside testFunction1() you have a local variable called ref , which is a pointer containing the value maddr . testFunction1()里面你有一个名为ref的局部变量,它是一个包含值maddr的指针。

When you delete ref , you deallocate the area of memory containing a TestClass object, whose address is maddr . delete ref ,取消分配包含TestClass对象的内存区域,该对象的地址为maddr

Then you allocate a new memory area: 然后分配一个新的内存区域:

TestClass *locTest = new TestClass();

and locTest contains its address, let's call it m1addr . locTest包含它的地址,我们称之为m1addr

Then you use ref to access the memory area at m1addr and change the int test value to 2 . 然后使用ref访问m1addr的内存区域并将int test值更改为2

This instruction: 这条指令:

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

outputs 2 as expected. 按预期输出2

Now, back to main , you have lost any handler to the area containing a TestClass object whose address is m1addr (that is, you are leaking memory) and the area pointed to by testObj is not allocated anymore. 现在,回到main ,你丢失了包含TestClass对象的区域的任何处理程序,该对象的地址是m1addr (也就是说,你正在泄漏内存)并且testObj指向的区域不再被分配。

When you use testObj again, you access an area of memory starting at maddr , which has been cleaned. 当您再次使用testObj时,您将访问从maddr开始的已清理的内存区域。 The effect of accessing testObj->test is undefined behavior. 访问testObj->test的效果是未定义的行为。

What you experience could be do to the fact that when you run your code maddr == m1addr , but this can only happen by chance, you cannot rely on this. 你经历的事情可能是这样的事实:当你运行你的代码maddr == m1addr ,但这只能偶然发生,你不能依赖于此。

Odds are the new object (with a 2) is being created where the old deleted object (with a 1) used to be. 赔率是新对象(带有2)正在创建旧已删除对象(带有1)的位置。 Your original pointer still points to that location so when you access it you accidentally access the new object (with a 2). 您的原始指针仍然指向该位置,因此当您访问它时,您不小心访问了新对象(使用2)。

TestClass *ref in the parameter to testFunction1 and TestClass *testObj in main are 2 different pointers to the same thing, they are not the same pointer though. TestClass *参数中的参数testFunction1和TestClass * testObj在main中是2个不同的指向同一个东西,它们虽然不是同一个指针。 If you want to delete and reallocate an object inside a function/method you can use a pointer to a pointer as the parameter. 如果要删除并重新分配函数/方法中的对象,可以使用指针作为参数。

As others have mentioned , after testfunction1 you're accessing an object that was deleted within testfunction1 which as also mentioned is undefined behaviour. 正如其他人所提到的,在testfunction1之后,你正在访问一个在testfunction1中被删除的对象,其中也提到了未定义的行为。 The memory being pointed to by the dangling pointer was released during the delete but the contents are likely to still be there until the memory location is reallocated during another call to new. 在删除过程中释放了悬空指针指向的内存,但内容可能仍然存在,直到在另一次调用new期间重新分配内存位置。 So you are using unallocated space that could be overwritten very easily at anytime. 因此,您使用的是未分配的空间,可以随时轻松覆盖。

Hope this helps 希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM