C++ delete - It deletes my objects but I can still

2018-12-31 02:30发布

I have written a simple, working tetris game with each block as an instance of a class singleblock.

class SingleBlock
{
    public:
    SingleBlock(int, int);
    ~SingleBlock();

    int x;
    int y;
    SingleBlock *next;
};

class MultiBlock
{
    public:
    MultiBlock(int, int);

    SingleBlock *c, *d, *e, *f;
};

SingleBlock::SingleBlock(int a, int b)
{
    x = a;
    y = b;
}

SingleBlock::~SingleBlock()
{
    x = 222;
}

MultiBlock::MultiBlock(int a, int b)
{
    c = new SingleBlock (a,b);
    d = c->next = new SingleBlock (a+10,b);
    e = d->next = new SingleBlock (a+20,b);
    f = e->next = new SingleBlock (a+30,b);
}

I have a function that scans for a complete line, and runs through the linked list of blocks deleting the relevant ones and reassigning the ->next pointers.

SingleBlock *deleteBlock;
SingleBlock *tempBlock;

tempBlock = deleteBlock->next;
delete deleteBlock;

The game works, blocks are deleted correctly and everything functions as it is supposed to. However on inspection I can still access random bits of deleted data.

If I printf each of the deleted singleblocks "x" values AFTER their deletion, some of them return random garbage (confirming the deletion) and some of them return 222, telling me even though the destructor was called the data wasn't actually deleted from the heap. Many identical trials show it is always the same specific blocks that are not deleted properly.

The results:

Existing Blocks:
Block: 00E927A8
Block: 00E94290
Block: 00E942B0
Block: 00E942D0
Block: 00E942F0
Block: 00E94500
Block: 00E94520
Block: 00E94540
Block: 00E94560
Block: 00E945B0
Block: 00E945D0
Block: 00E945F0
Block: 00E94610
Block: 00E94660
Block: 00E94680
Block: 00E946A0

Deleting Blocks:
Deleting ... 00E942B0, X = 15288000
Deleting ... 00E942D0, X = 15286960
Deleting ... 00E94520, X = 15286992
Deleting ... 00E94540, X = 15270296
Deleting ... 00E94560, X = 222
Deleting ... 00E945D0, X = 15270296
Deleting ... 00E945F0, X = 222
Deleting ... 00E94610, X = 222
Deleting ... 00E94660, X = 15270296
Deleting ... 00E94680, X = 222

Is being able to access data from beyond the grave expected?

Sorry if this is a bit long winded.

13条回答
与风俱净
2楼-- · 2018-12-31 02:58

Although it's possible that your runtime doesn't report this error, using a proper error-checking runtime such as Valgrind will alert you to the use of memory after it has been freed.

I recommend that if you write code with new/delete and raw pointers (rather than std::make_shared() and similar), that you exercise your unit tests under Valgrind to at least have a chance of spotting such errors.

查看更多
忆尘夕之涩
3楼-- · 2018-12-31 02:59

The system does not clear the memory when you release it via delete(). The contents are therefore still accessible until the memory is assigned for reuse and overwritten.

查看更多
其实,你不懂
4楼-- · 2018-12-31 03:00

Delete doesn't delete anything -- it just marks the memory as "being free for reuse". Until some other allocation call reserves and fills that space it will have the old data. However, relying on that is a big no-no, basically if you delete something forget about it.

One of the practices in this regard that is often encountered in libraries is a Delete function:

template< class T > void Delete( T*& pointer )
{
    delete pointer;
    pointer = NULL;
}

This prevents us from accidentally accessing invalid memory.

Note that it is perfectly okay to call delete NULL;.

查看更多
大哥的爱人
5楼-- · 2018-12-31 03:00

delete deallocates the memory, but does not modify it or zero it out. Still you should not access deallocated memory.

查看更多
零度萤火
6楼-- · 2018-12-31 03:02

It is what C++ calls undefined behaviour - you might be able to access the data, you might not. In any case, it is the wrong thing to do.

查看更多
时光乱了年华
7楼-- · 2018-12-31 03:04

Yes, it can be expected at times. Whereas new reserves space for data, delete simply invalidates a pointer created with new, allowing data to be written at the previously reserved locations; it doesn't necessarily delete the data. However, you shouldn't rely on that behaviour because the data at those locations could change at any time, possibly causing your program to misbehave. This is why after you use delete on a pointer (or delete[] on an array allocated with new[]), you should assign NULL to it so that you can't tamper with an invalid pointer, assuming you won't allocate memory using new or new[] before using that pointer again.

查看更多
登录 后发表回答