C++语义与内存泄漏

binbin 2006-11-16 09:36:01
这两天在看java,突然把其中的一些东西与C++联想到一起,由于java所有对象都是引用类型,又有垃圾回收机制,在类的实例的创建上的行为也有很大的不同,于是编了段C++代码验证,现在在想到底下面的代码到底会不会有内存泄漏问题呢?

#include <iostream>
using namespace std;
class myclass
{
myclass* _this;
private://把构造函数变为私有,可以禁止用户直接生成实例而用下面的静态方法来生成
myclass()
{
cout << "Begin" << endl;
}
public:
~myclass()
{
cout << "End" << endl;
}
static myclass& buildmyclass()//让这个静态方法来创建类的实例
{
myclass* o = new myclass();
o->_this = o;
return *o;
}
};

void test()
{
myclass p = myclass::buildmyclass();//调用静态方法生成实例
}

int main()
{
test();
}

程序的结果是
Begin
End
也就是说构造函数与析构函数都被调用了,但buildmyclass静态方法中的new没有与之对应的delete,简而言之,当一个函数中new了一个对象(按理应该分配在堆中)并将其作为引用返回给调用函数中的一个自动变量(按理应该分配在栈中并在出了作用域自动释放),那么编译器的行为是什么呢?这里很显示自动变量出了作用域后调用了析构函数,那么堆内存有没有被释放呢?
...全文
6268 70 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
70 条回复
切换为时间正序
请发表友善的回复…
发表回复
lichaohui 2006-11-26
  • 打赏
  • 举报
回复
有 new 则必须有 delete 否则就会内存泄漏
liuyingwu 2006-11-23
  • 打赏
  • 举报
回复
感觉还是有点迷茫 呵呵 学习..
gapwind 2006-11-23
  • 打赏
  • 举报
回复
mark
AbnerChai 2006-11-23
  • 打赏
  • 举报
回复
上面最后test()有点笔误,应该是,
void test(void)
{
myclass *p = NULL;
p = myclass::get_myclass();
//p->xxxx;
myclass::rel_myclass();
}
AbnerChai 2006-11-23
  • 打赏
  • 举报
回复
C++ 中常用的单根模式通常是这么写的,

//myclass.h

#include <iostream>

using namespace std;

class myclass
{
private:
static myclass* _this;
myclass(void);
~myclass(void);

public:
static myclass* get_myclass(void);
static void rel_myclass(void);
};

//myclass.cpp

#include<iostream>

myclass* myclass::_this = NULL;

myclass::myclass(void) {
}

myclass::~myclass(void) {
}

myclass* myclass::get_myclass(void) {
if(_this == NULL){
_this = new myclass();
if(_this == NULL) {
error_log(...);
}
}
return _this;
}

void myclass:rel_myclass(void) {
if(_this != NULL){
delete _this;
_this = NULL;
}
}
//main.cpp
#include "myclass.h"

void test(void)
{
myclass *p = NULL;
p = myclass->get_myclass();
//p->xxxx;
p->rel_myclass();
}

int main()
{
test();
}



hyg2008 2006-11-22
  • 打赏
  • 举报
回复
guangbin79() 的应该是正解,不过this != _this是不是应该换成this == _this?

#include <iostream>
using namespace std;
class myclass
{
myclass* _this;
private://把构造函数变为私有,可以禁止用户直接生成实例而用下面的静态方法来生成
myclass() : _this(NULL)
{
cout << "Begin" << endl;
}
public:
~myclass()
{
if (this != _this)//--------是不是应该换成this == _this?
{
delete _this;
}

cout << "End" << endl;
}
static myclass& buildmyclass()//让这个静态方法来创建类的实例
{
myclass* o = new myclass();
o->_this = o;
return *o;
}
};

void test()
{
myclass p = myclass::buildmyclass();//调用静态方法生成实例
}

int main()
{
test();
}
axx1611 2006-11-22
  • 打赏
  • 举报
回复
回楼上 个人觉得的确应该是!=号
实质上
myclass p = myclass::buildmyclass();//调用静态方法生成实例
等价于
myclass p(myclass::buildmyclass());
即调用了默认的拷贝构造函数:
myclass::myclass(myclass &_noname)
{
_this = _noname->_this;
}
可见p的内存(p->this目标)是这条语句创建出来的,而p->_this的内存是myclass::buildmyclass()创建的。
故要在p销毁的同时销毁掉myclass::buildmyclass()创建的内存,就应该delete _this。此时this必然是不等于_this的。

如果还不明白可以这么写:

myclass *p = new myclass(myclass::buildmyclass()); // 创建了2个myclass对象
//using p
delete p; // 销毁了2个myclass对象(p和p->_this)

这种方法虽然看似实现回收机制,实际上没什么效率,内存总是双份,每次还要调用拷贝构造函数。。。


jw212 2006-11-21
  • 打赏
  • 举报
回复
mark
someone 2006-11-20
  • 打赏
  • 举报
回复
#include<iostream>
using namespace std;

class myclass
{
private:
//myclass *_this;
myclass() { cout << this << " begin" << endl; }
public:
~myclass() { cout << this << " end" << endl; }
static myclass& buildmyclass() { myclass *po = new myclass(); /*po->_this = po;*/ return *po; }
};

void test()
{
myclass p = myclass::buildmyclass();
}

int main(int argc, char *argv[])
{
cout << "hello world" << endl;
test();

return 0;
}

---------------------
运行结果:
hello world
0x3d3e98 begin
0x22ff60 end
请按任意键继续. . .
someone 2006-11-20
  • 打赏
  • 举报
回复
#include<iostream>
using namespace std;

class myclass
{
private:
//myclass *_this;
myclass() { cout << this << " begin" << endl; }
public:
~myclass() { cout << this << " end" << endl; }
static myclass& buildmyclass() { myclass *po = new myclass(); /*po->_this = po;*/ return *po; }
};

void test()
{
myclass &p = myclass::buildmyclass();
}

int main(int argc, char *argv[])
{
cout << "hello world" << endl;
test();

return 0;
}

---------------------
运行结果:
hello world
0x3d3e98 begin
请按任意键继续. . .
hwpass 2006-11-20
  • 打赏
  • 举报
回复
mark
panzer_v 2006-11-19
  • 打赏
  • 举报
回复
其实子函数可以先将要返回的数压栈,然后再弹出来,再返回。调用者可以在栈中找到返回的数。turbo c好象就是这样做的。
zenny_chen 2006-11-19
  • 打赏
  • 举报
回复
刚才一直在照顾那个月经贴,现在终于被踢到其它地方去了。

回楼上:

不同的编译器可能有不同的函数返回方式,但是:对于
type& func(void)
{
type *p = new type;

return *p;
}
这个函数的返回是安全的。因为指针p所指的并不是局部变量,而是动态存储空间,因此这段数据内容不会因为出栈而被破坏。而引用本身就是一个“指针”,只是比较特殊而已。因此在概念上,这样的写法本身没有什么不妥。
panzer_v 2006-11-19
  • 打赏
  • 举报
回复
根据lz的例子,可以这样定论:一般对象声明必然是在堆栈中分配对象空间,而用new产生对象必然是在堆中分配对象空间。
myclass p = myclass::buildmyclass();//调用静态方法生成实例
这句可能打错了,应为:
myclass &p = myclass::buildmyclass();//调用静态方法生成实例
这样的声明会导致对象的复制。即产生一个堆栈中的p。这个p会在作用域退出运行时被析构。而在堆中的对象必须用delete才会发声析构和堆空间的释放。
lin_style 2006-11-19
  • 打赏
  • 举报
回复
一对begin end不会说明什么问题。
lin_style 2006-11-19
  • 打赏
  • 举报
回复
虽然编译无问题,可以运行,
但是该堆空间无法回收,因为没有指向该堆空间的指针,程序不断重复运行,堆空间也在不断流失。
如果坚持要从堆中分配,必须要一些代价,
比如 做个加法返回
void fn(T& a,T& b){
T* pc=a+b;
T* c=*pc;
delete pc;
}
这样通过值返回时,将有一个临时对象在调用者栈空间查声,复制给被调函数result对象。此时要考虑到临时对象的作用域

楼主情况和适合在返回值参加运算分析讨论,例运算符重载
systemspy 2006-11-19
  • 打赏
  • 举报
回复
拷漏了

static myclass& buildmyclass()
{
static myclass o = myclass();

o->_this = o;

return o;
}
systemspy 2006-11-19
  • 打赏
  • 举报
回复
static myclass& buildmyclass()
{
myclass o = myclass();
o->_this = o;

return o;
}

谁叫你new了不delete的
zenner3000 2006-11-19
  • 打赏
  • 举报
回复
mark
yxhua 2006-11-19
  • 打赏
  • 举报
回复
sorry,上一个帖子分析有错误,声明作废!
加载更多回复(50)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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