这几种内存释放方式,正确与否,能不能完全释放内存?

youngwolf 2008-06-27 12:25:57
一:
class A;
class B : public A
//假设类B比类A要大,则:

A* pA = new B;
delete pA;


二:
class A;

void* p = new A;
delete p;


三:
struct s
{
int i;
int j;
};

LPBYTE pData = new BYTE[100];
struct s* ps = (struct s*) pData;
delete ps;


四:
class A
{
void Release(){delete this;}
};

class B : public A
{
int i;
};

B* pb = new B;
pb->Release();



最近我进了一家人数达到六七百人的大公司,我看了一下他们的代码,
上面是我看到的3种内存释放方式,我对程序的正确性表示怀疑!

还有,他们居然用__stdcall来修改可变参数的函数!可是奇怪的是,编译没有问题,运行也没有问题,可能对这个问题,我自己也不懂!
或者,这个函数根本没有执行到。
...全文
1140 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
scj_201 2011-12-08
  • 打赏
  • 举报
回复
好贴, 学习中!!!!!!!!!!
是梦是醒 2010-07-02
  • 打赏
  • 举报
回复
经典!!!!!收藏了
sanshao27 2008-06-30
  • 打赏
  • 举报
回复
是释放8字节,但是如果A没有虚析构,B的析构是不会调用的。如果在B中又申请了内存,那么这时候B就无法释放它自己申请的内存。如果B类本身没有申请内存的动作,这段code运行起来确实没有问题。
3楼分析的已经很精辟了。
我看你有戏 2008-06-30
  • 打赏
  • 举报
回复

没有把握的东西就先不要用啊

mark
gamedragon 2008-06-29
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 jameshooo 的回复:]
delete接受的参数类型是void*,不用管内存大小,只要void*的值正确就没有问题
[/Quote]
最终传进去的参数确实如此,但在传指针进去之前编译器会做些trick,可以把多继承的这种指针变换回最早分配的原始地址。

class C : public A, public B

C *pc= new C;
A *pa = (A *)pc;
B *pb = (B *)pc;

这种情况,有可能是pc=0x12345678,pa=0x12345678,pb=0x12345688

如果再考虑虚继承的话就更复杂了。
gamedragon 2008-06-28
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 yang79tao 的回复:]
class A;
class B : public A
//假设类B比类A要大,则:

假设A和B的析构都不是虚的,比如A占4字节,B占8个字节,则:
A* pA = new B;
delete pA;
最后的delete pA; 到底是释放4字节还是8字节?我看了二楼的解释,仍然没有找到这个问题的答案。
[/Quote]
是释放8字节,但是如果A没有虚析构,B的析构是不会调用的。如果在B中又申请了内存,那么这时候B就无法释放它自己申请的内存。如果B类本身没有申请内存的动作,这段code运行起来确实没有问题。

上面这段delete操作翻译成伪代码:
pA->~A();
free((void *)pA);
分配内存的时候已经记录了当前分配内存块的大小,所以释放分配的内存块没有问题,有问题的是对象自己分配的内存。
jieao111 2008-06-28
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 yang79tao 的回复:]
class A;
class B : public A
//假设类B比类A要大,则:

假设A和B的析构都不是虚的,比如A占4字节,B占8个字节,则:
A* pA = new B;
delete pA;
最后的delete pA; 到底是释放4字节还是8字节?我看了二楼的解释,仍然没有找到这个问题的答案。
[/Quote]
这不是c++的知识吗,可以看看c++语法书.当然释放4字节,要想释放8字节,用虚析构函数
lizhigang34 2008-06-28
  • 打赏
  • 举报
回复
mark,
学习了
gamedragon 2008-06-28
  • 打赏
  • 举报
回复
我对new delete的理解:
delete这个操作符实际上就是先执行对象的析构操作,再释放内存。有无[]是指定要释放的是一组object,要对每个对象都执行析构。

由此:
一、如A有虚析构,OK;否则,B析构不会被执行。
二、A对象本身内存被释放,但A析构不会被执行,因为delete的不是A对象,尽管指针一样。
三、普通structure,没有析构动作也不会产生影响,OK。
四、同一。在类内部delete自己和在外面delete效果一样。
jameshooo 2008-06-28
  • 打赏
  • 举报
回复
delete接受的参数类型是void*,不用管内存大小,只要void*的值正确就没有问题
ChrisAK 2008-06-28
  • 打赏
  • 举报
回复
这个...如果是VC的话问题应该不大.
撇开析构函数的问题.
三的情况LZ应该是觉得s和pData申请的内存大小不一样.
new/malloc都是在堆上分配内存.调用的是HeapAlloc函数.
(具体可以去看VC自带的CRT源码)而对应的HeapFree是不需要
知道内存块有多大的.

不过这样的写法极不规范,且依赖于编译器的实现,很不好.
gamedragon 2008-06-28
  • 打赏
  • 举报
回复
LS说的仅仅是单继承的情况,如果是多继承的话

class C : public A, public B

C *pc= new C;
A *pa = (A *)pc;
B *pb = (B *)pc;

这时候,(void *)pa、(void *)pb和(void *)pc不是一样的。但delete的时候,编译器会把真正分配时的指针算出来的。
pigsanddogs 2008-06-28
  • 打赏
  • 举报
回复
operator delete (void*) 要求的是个地址, 除去一些c++要求的判定外,
本质上就是转到了free。 “释放”只是把某个内存块释放, 要求传的是一个地址,
堆管理器会根据这个地址计算出这个地址当时分配的大小来释放, 或者错误。
jameshooo 2008-06-28
  • 打赏
  • 举报
回复
class B : public A

B* pb = new B;
A* pa = (A*)pb;

assert(pa==pb);
assert((void*)pa != (void*)pb);
搞清这两个断言就知道会不会出问题了。
bengold1979 2008-06-28
  • 打赏
  • 举报
回复
问题探讨的很深,有助于学习
cnzdgs 2008-06-28
  • 打赏
  • 举报
回复
new和delete是分配的释放内存块,new的时候分配是多少delete就释放多少,只于指针的值有关(根据指针找出分配的地址和大小),与delete的指针类型无关,指针类型决定使用哪个类的析构函数。如果把某个类的指针值转换为其祖先类的指针类型来delete,如果是虚析构函数,则可正常调用,如果不是,则只调用祖先类的析构函数。
birchlin 2008-06-28
  • 打赏
  • 举报
回复
学习! 不错!
Crob 2008-06-28
  • 打赏
  • 举报
回复
1、2、3、4理论上都没有错误,其中1、2要满足以下前提。
1的正确前提是基类析构函数声明为virtual
4的正确前提是release后再也没有其它代码使用该指针,因为该指针所指对象已经被delete this,它已经是一个野指针。
gamedragon 2008-06-28
  • 打赏
  • 举报
回复
写一段模拟new和delete的伪代码:
p = new A;
=>
p = malloc(sizeof(A));
p->A();

p = new A[N];
=>
p = malloc(sizeof(A)*N);
for(i=0; i<N; ++i)
p[i].A();

--------------------

A *p;
delete p;
=>
p->~A(); // 注意:这里调用的析构只和p的类型有关
free((void *)p);

delete[] p;
=>
for(i=0;i<size/sizeof(A);++i) // 因为分配是已经知道了总共分配了多大的内存,所以可以算出对象个数
p[i].~A();
free((void *)p);
cnzdgs 2008-06-27
  • 打赏
  • 举报
回复
这几种方式都会释放内存,delete只要指针的值对就会释放内存。区别在于:
一、如果不是虚析构函数,delete时不会执行~B()。
二、不是执行析构函数。
三、没问题,但要注意,struct与class基本是相同的,delete时也会自动执行析构函数。
四、同一。

使用__stdcall定义可变参数的函数时,__stdcall会自动忽略。
加载更多回复(22)

16,467

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧