转载来自:http://blog.itpub.net/7728585/viewspace-2123621/

今天遇到一个问题,C++编程时,函数中new一块内存,然后将申请内存的指针作为返回值。怎么delete内存?

首先明白几个基础
1、函数按值传递和按值返回的时候都会调用复制构造函数
2、一般在函数体内定义的栈变量是不能返回其地址或者引用给主调函数的,因为在函数结束的时候这些栈变量将释放
3、可以使用new的方式建立堆内存的方式,然后返回引用或者指针,因为new这种方式建立的堆内存并不随函数的结束而结束,
     而指针变量释放但是指针本生的值已经返回。同时也可以按值放回,但是这种情况下将可能出现内存泄露
来看下面的代码

/*************************************************************************
> File Name: testcc.cpp
> Author: gaopeng
> Mail: gaopp_200217@163.com
> Created Time: Thu 01 Sep 2016 09:06:53 PM CST
************************************************************************/ #include<iostream>
using namespace std; class testa
{
private:
int i;
public:
testa(const int m){
cout<<"create a object\n";
i=m;
}
const int& geti() const {
return i;
}
testa(const testa& m ){
cout<<"copy funcation\n";
i=m.i;
}
~testa(){
cout<<"discard a object\n";
}
testa operator=(const testa& c)
{
cout<<"= funcation\n";
i = c.i;
} }; testa func()
{
cout<<"in func function\n";
//testa p(10);
testa* p = new testa();
cout<<p<<endl;
cout<<"end func\n";
return *p;
} int main(void)
{
testa m = func(); //copy
cout<<&m<<endl;
cout<<m.geti()<<endl;
return ;
}

程序说明:
这里testa* p = new testa(1);建立一块堆内存
这里return *p;按值返回,按值返回会调用复制构造函数给值赋予给新建个对象m
程序结束后调用m的析构函数,但是这里new出来的内存空间已经没有可以指向的指针
因为p已经释放,而返回的是*p,这块内存已经泄露。我们跑一下看看:
in func function   --调用func函数
create a object   --new创建的testa的堆内存 testa* p = new testa(1);
0x1914010        --new的地址 cout<<p<<endl;
end func           --结束func函数 cout<<"end func\n";
copy funcation   --按值返回调用复制构造函数,将值赋予给新的变量m testa m = func();
0x7fffb9c438a0  --新对象m的地址cout<<&m<<endl;
1
discard a object  --析构函数释放栈对象m的空间

这里我们发现new的堆内存空间没有被析构,那么内存已经泄露。
那么我们怎么不大量改变程序的情况下来消除这种问题呢
当然是使用指针或者引用来返回。

testa* func()
{
cout<<"in func function\n";
//testa p(10);
testa* p = new testa();
cout<<p<<endl;
cout<<"end func\n";
return p;
} int main(void)
{
{
testa* m = func(); //copy
cout<<m<<endl;
cout<<m->geti()<<endl;
delete m;
}
return ;
}

这一在main中我把定义m指针到删除放到了一个block中,这样在block结束的时候就释放了m避免了空指针的存在。
下面是引用。

testa& func()
{
cout<<"in func function\n";
//testa p(10);
testa* p = new testa();
cout<<p<<endl;
cout<<"end func\n";
return *p;
} int main(void)
{
{
testa& m = func(); //copy
cout<<&m<<endl;
cout<<m.geti()<<endl;
delete &m;
}
return ;
}

同样main中的这个程序块是为了避免空引用
输出如下:
in func function  
create a object
0x1989010
end func
0x1989010   
1
discard a object

可以看到地址都相同,最后的析构函数是我调用delete执行的。

转载:C++函数中new一块内存,作为返回值的更多相关文章

  1. (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAAE0CAIAAAB7LwoKAAAgAElEQVR4nO2dy6sc152A6+/R2mXwSn ...

  2. Ajax - 在函数中使用Ajax怎么使用返回值 - Ajax赋值给全局变量异常的解决方法

    要使用异步操作:  async : false,//取消异步操作 //添加节点函数 function InsertNode(nodenum, nodename, type) { var returnv ...

  3. 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存

    申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...

  4. Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值

    Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...

  5. c#中命令copy已退出,返回值为1

    c#中命令copy已退出,返回值为1 本正经的道:董姐刚才你说的修心养性其中的'修心'我 有孕在身刚好由戴梦瑶顶替了她的位置按照的指示 ╋旆呆 湎术葶页 邾箕砜笳 烦璜卿廑 奶奶个腿儿的等下次非让你 ...

  6. ascii#ascii,对象类中找__repr__,获取其返回值

    #!/usr/bin/env python #ascii,对象类中找__repr__,获取其返回值 class Foo : def __repr__(self): return "hello ...

  7. Python--day10(函数(使用、分类、返回值))

    1.  函数 1.  函数: 完成特定功能的代码块,作为一个整体,对其进行特定的命名,该名字就代表这函数 现实中:很多问题要通过一些工具进行处理 => 可以将工具提前生产出来并命名 =>通 ...

  8. Python3学习之路~3.1 函数基本语法及特性、返回值、参数、局部与全局变量

    1 函数基本语法及特性 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 语法定义: d ...

  9. Golang中defer、return、返回值之间执行顺序的坑

    原文链接:https://studygolang.com/articles/4809 Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多go ...

随机推荐

  1. VMware中四种网络连接模式的区别

    安装好VMwareWorkstations之后,进行虚拟机网络配置时有四种网络连接方式,桥接.仅主机.NAT.LAN区段. 之所以有不同的模式,在我看来是为了满足不同的网络需求,总的来说:桥接.NAT ...

  2. 使用python操作word

    有两种方式: 使用win32com 使用docx 1.使用win32com扩展包 只对windows平台有效 代码: # coding=utf-8 import win32com from win32 ...

  3. java翻转字符串中的单词

    效果: 输入: "java and python" 输出: "avaj dna nohtyp" 代码: 版本1: 不考虑字符串开头有空格,单词间有多个空格空格的 ...

  4. P2871 手链

    传送 这个题的数据限制没有翻译出来,所以有可能产生爆内存现象 再此翻译一下:1<=n(物品个数)<=3402,1<=M(总重量)<=12880 (就这两个有点用) 显然这是一个 ...

  5. Spring Boot 容器选择 Undertow 而不是 Tomcat

    Spring Boot 内嵌容器Undertow参数设置 配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动 ...

  6. Java学习——使用Static修饰符

    程序功能:通过两个类 StaticDemo.LX4_1 说明静态变量/方法与实例变量/方法的区别. package Pack1; public class Try { public static vo ...

  7. Oracle 存储过程起步

    存储过程的注释不能写在第一行 select后面要有into create or replace procedure DelEmp(v_empno in emp.empno%type) AS No_re ...

  8. Authentication required (packagist.phpcomposer.com) 账号密码到哪里获取?

    安装好composer后,执行composer install 报这个错 面对这个错有两种方法.1,他说你的composr 版本不够稳定,composer update 一下,或者 composer ...

  9. RabbitMQ用户角色及权限控制(转)

    转载至:https://blog.csdn.net/awhip9/article/details/72123257 2017年05月15日 10:39:26 awhip9 阅读数:3538   ### ...

  10. ado.net 中事务的使用

    SqlHelper 类方法中启用事务 public static int UpdateByTran(List<string> sqlList) { SqlConnection conn = ...