简体   繁体   中英

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:

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

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:

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:

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

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

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

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. 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.

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 .

Now, this instruction:

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

outputs 1 , as expected.

Inside testFunction1() you have a local variable called ref , which is a pointer containing the value maddr .

When you delete ref , you deallocate the area of memory containing a TestClass object, whose address is maddr .

Then you allocate a new memory area:

TestClass *locTest = new TestClass();

and locTest contains its address, let's call it m1addr .

Then you use ref to access the memory area at m1addr and change the int test value to 2 .

This instruction:

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

outputs 2 as expected.

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.

When you use testObj again, you access an area of memory starting at maddr , which has been cleaned. The effect of accessing testObj->test is undefined behavior.

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.

Odds are the new object (with a 2) is being created where the old deleted object (with a 1) used to be. Your original pointer still points to that location so when you access it you accidentally access the new object (with a 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. 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. 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. So you are using unallocated space that could be overwritten very easily at anytime.

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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