• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C++ 传值 避免 内存泄漏的一个技巧。[new 了以后,不一定要delete][修正,new后一定de ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

不用看了,2年前,自己功夫不够,没有想清楚,也觉得奇怪呢,忘记了  拷贝构造函数 这一说,结果导致本文 没有意义了。

其实我根本没有使用过这个想法的,后来的工作依然是 一个 new 一个delete。

原来以为 C++ 会自动进行类型转换,我错了。

 

 

再次声明,以下是错误的,现在经过修正了。红色为修正后。

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

直接上代码。其实这是对类 和 指针 理解的一个案例。

#include<stdio.h>
#include<iostream>
using std::endl;
using std::cout;
/*****************
事实证明: 类的一般实例对象 只在所在函数有效,函数结束,这个类实例自动释放资源。
***************/
#define DEBUG_FUNCTION_LINE() printf("#当前所在函数[%p]  %s() 位于%d行\n",this,__FUNCTION__,__LINE__)


class CServer1{
public:
    int isExit;
public:
    CServer1(){
        this->isExit=0;
        DEBUG_FUNCTION_LINE();
    };

      CServer1(const CServer1&copy){
           DEBUG_FUNCTION_LINE();
           this->isExit=copy.isExit;
      };

~CServer1(){
        this->isExit=1;
        DEBUG_FUNCTION_LINE();
    };
};

////下面这个 函数 是否有缺陷???
CServer1  getPtrFunc (){
    CServer1 *s=new CServer1();
    s->isExit=15;
    return  *s;//如果不用指针,局部变量会有错误的。Error 返回局部变量地址 是错误的。
//这里错误了,函数返回,发生了默认拷贝构造函数,函数内部的 new 没有释放掉,倒是新派生出了一个返回值 的类。那个 可以在本函数外围 自动释放掉。
}; void func2(){ CServer1 foo; foo=getPtrFunc();//这样赋值,是否 会存在内存泄漏???当然不会 实际存在内存泄漏了。 std::cout<<" foo->isExist=" << foo.isExit <<endl;//=15 是正常的 //结束后,会执行 释放 操作的! }; void func3(){ getPtrFunc();//这样赋值,是否 会存在内存泄漏???当然不会当然会 new了就要delete的 //结束后,会执行 释放 操作的! }; int main(){ func2();//两次 析构函数 其实是三次构造,两次析构,错误的。 cout<<"@@@ Func2 完毕。"<<endl; func3();//一次 析构函数 //这个函数证明了 很是OK !太错误了,看结果就知道 其实是 两次构造函数,一次析构函数 cout<<"@@@ Func3 完毕。"<<endl;return 0; }

结果:

#当前所在函数 CServer1::CServer1() 位于18行
#当前所在函数 CServer1::CServer1() 位于18行
#当前所在函数 CServer1::~CServer1() 位于22行
 foo->isExist=15
#当前所在函数 CServer1::~CServer1() 位于22行
@@@ Func2 完毕。
#当前所在函数 CServer1::CServer1() 位于18行
#当前所在函数 CServer1::~CServer1() 位于22行
@@@ Func3 完毕。





 

#当前所在函数[0x7fff5a39ec08] CServer1() 位于17行

#当前所在函数[0x7fbb60c03a00] CServer1() 位于17行

#当前所在函数[0x7fff5a39ec00] CServer1() 位于20行

#当前所在函数[0x7fff5a39ec00] ~CServer1() 位于29行

 foo->isExist=15

#当前所在函数[0x7fff5a39ec08] ~CServer1() 位于29行

@@@ Func2 完毕。

 

#当前所在函数[0x7fbb60c03a10] CServer1() 位于17行

#当前所在函数[0x7fff5a39ec18] CServer1() 位于20行

#当前所在函数[0x7fff5a39ec18] ~CServer1() 位于29行

@@@ Func3 完毕。

 

 

构造函数 和 析构函数 是一一对应的。所以看到上面 没有少任何一个函数 ,说明 没有内存泄漏。

我用了一个 new ,但是没有delete。没有内存泄漏。

new的类,利用 函数返回值(以前我一直认为返回值 如果是类,必须得用指针呢,其实不用),直接返回类的实例对象,而不是指针,这样,new出来的就不需要delete,也会自然调用 析构函数了。

 

哈哈,,我好像 是 一个 小学生 突然发现 吸铁石 S N 互相吸引 ,SS NN互相排斥 一样。。。[果然跟小学生似的]

 

 突然又想 反着来,返回一个指针 类型的,必须 delete 才能避免内存泄漏。但是 发现 使用函数返回值 我错了一次。。。

#include<stdio.h>
#include<windows.h>
#include<iostream>
using std::endl;
using std::cout;
/*****************
事实证明: 类的一般实例对象 只在所在函数有效,函数结束,这个类实例自动释放资源。
***************/
#define DEBUG_FUNCTION_LINE() printf("#当前所在函数[%p] %s() 位于%d行\n",this,__FUNCTION__,__LINE__)


class CServer1{
public:
    int isExit;
public:
    CServer1(){
        this->isExit=0;
        DEBUG_FUNCTION_LINE();
    };
      CServer1(const CServer1&copy){
           DEBUG_FUNCTION_LINE();
           this->isExit=copy.isExit;
      };
~CServer1(){ this->isExit=-1; DEBUG_FUNCTION_LINE(); }; }; ////下面这个 函数 是否有缺陷??? CServer1 getPtrFunc (){ CServer1 *s=new CServer1(); s->isExit=15; return *s;//如果不用指针,局部变量会有错误的。Error 返回局部变量地址 是错误的。 //这句话 会 调用一个 析构函数 }; void func1(){ CServer1 foo; cout<<"开始 调用getPtrFunc返回值"<<endl; foo=getPtrFunc();//这样赋值,是否 会存在内存泄漏???当然不会 cout<<"结束 调用getPtrFunc返回值"<<endl; std::cout<<" foo->isExist=" << foo.isExit << " [=15 是正常的]" <<endl;// //结束后,会执行 [拷贝后的对象]释放 操作的! }; void func2(){ cout<<"开始 调用getPtrFunc返回值"<<endl; getPtrFunc();//这样赋值,是否 会存在内存泄漏???当然不会 cout<<"结束 调用getPtrFunc返回值"<<endl; //结束后,会执行 释放 操作的! }; CServer1 func31(){ CServer1 * s=new CServer1(); s->isExit=25; *s=getPtrFunc(); std::cout<<"In Func31: foo->isExist=" << s->isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return *s;//本句 导致new的对象 析构函数 被调用了。。。特无语啊。 //return CServer1(); }; CServer1 * func3(){ //此函数 第一个版本 //CServer1 *s; //s=&func31();//这一句 彻底失败了。 应该是赋值 而不是 引用地址!! //cout<<"@@@ Func3.1完毕。"<<endl; //Sleep(1); //std::cout<<"In Func3: foo->isExist=" << s->isExit <<endl;//=15 是正常的 //此函数 第二个版本 正常,但是不是我想要的 /***** CServer1 s;//更改为 s 才正常了。 cout<<"开始 调用Func31。"<<endl; s=func31(); cout<<"结束 调用Func31。"<<endl; Sleep(1); std::cout<<"In Func3: foo->isExist=" << s.isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return NULL; *********/ //此函数 第三个版本,修改了返回值类型;此函数 如果不delete 会内存泄漏 CServer1 *ptr; ptr=new CServer1(); cout<<"开始 调用Func31。"<<endl; *ptr=func31(); cout<<"结束 调用Func31。"<<endl; Sleep(1); std::cout<<"In Func3: foo->isExist=" << (*ptr).isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return ptr; }; int main(){ func1();//两次 析构函数 cout<<"@@@ Func1 完毕。"<<endl<<endl; func2();//一次 析构函数 //这个函数证明了 很是OK ! cout<<"@@@ Func2 完毕。"<<endl<<endl; CServer1 * p=func3(); cout<<"@@@ Func3 完毕。"<<endl<<endl; delete p; cout<<"最后一个函数完成了,delete下 也就没有内存泄漏了!!"<<endl; Sleep(20000); return 0; } /* #当前所在函数 CServer1::CServer1() 位于18行 开始 调用getPtrFunc返回值 #当前所在函数 CServer1::CServer1() 位于18行 #当前所在函数 CServer1::~CServer1() 位于22行 结束 调用getPtrFunc返回值 foo->isExist=15 [=15 是正常的] #当前所在函数 CServer1::~CServer1() 位于22行 @@@ Func1 完毕。 开始 调用getPtrFunc返回值 #当前所在函数 CServer1::CServer1() 位于18行 #当前所在函数 CServer1::~CServer1() 位于22行 结束 调用getPtrFunc返回值 @@@ Func2 完毕。 #当前所在函数 CServer1::CServer1() 位于18行 开始 调用Func31。 #当前所在函数 CServer1::CServer1() 位于18行 #当前所在函数 CServer1::CServer1() 位于18行 #当前所在函数 CServer1::~CServer1() 位于22行 In Func31: foo->isExist=15 [=15 是正常的] #当前所在函数 CServer1::~CServer1() 位于22行 结束 调用Func31。 In Func3: foo->isExist=15 [=15 是正常的] @@@ Func3 完毕。 #当前所在函数 CServer1::~CServer1() 位于22行 最后一个函数完成了,delete下 也就没有内存泄漏了!!

 

#当前所在函数[0x7fff57113b48] CServer1() 位于18行

开始 调用getPtrFunc返回值

#当前所在函数[0x7f90e0403a00] CServer1() 位于18行

#当前所在函数[0x7fff57113b38] ~CServer1() 位于22行

结束 调用getPtrFunc返回值

 foo->isExist=15 [=15 是正常的]

#当前所在函数[0x7fff57113b48] ~CServer1() 位于22行

@@@ Func1 完毕。

 

开始 调用getPtrFunc返回值

#当前所在函数[0x7f90e0403a10] CServer1() 位于18行

#当前所在函数[0x7fff57113b58] ~CServer1() 位于22行

结束 调用getPtrFunc返回值

@@@ Func2 完毕。

 

#当前所在函数[0x7f90e0403a20] CServer1() 位于18行

开始 调用Func31。

#当前所在函数[0x7f90e0403a30] CServer1() 位于18行

#当前所在函数[0x7f90e0403a40] CServer1() 位于18行

#当前所在函数[0x7fff57113ab8] ~CServer1() 位于22行

In Func31: foo->isExist=15 [=15 是正常的]

#当前所在函数[0x7fff57113b38] ~CServer1() 位于22行

结束 调用Func31。

In Func3: foo->isExist=15 [=15 是正常的]

@@@ Func3 完毕。

 

#当前所在函数[0x7f90e0403a20] ~CServer1() 位于22行

最后一个函数完成了,delete下 也就没有内存泄漏了!!

 

*/

总结:

1.在getPtrFunc 函数中,虽然只有new,由于返回值 是 类实例  类型的,将指针 *p 返回,会在函数完成后自动销毁(即调用了和new对应delete 对应的 析构函数)。

2. 返回值类型为类实例的函数 的时候,不能对函数 使用 & 。正如 func3 的第一个版本,其实已经访问了释放过内存的区域了。(isExist=-1了)是不安全的。

3.上面说明,函数返回值 其实在取值的时候 是赋值,而不是 传递 地址。将 内存 拷贝,复制,有点 memcpy 的感觉。char[] 数组 如果可以这样赋值 多方便。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
使用ILMerge打包C#绿色免安装版程序发布时间:2022-07-13
下一篇:
设计模式C++描述----06.适配器(Adapter)模式发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap