转载来自: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. windows下怎么生成github的ssh公钥

    windows下如何生成github的ssh公钥: 1.首先你要安装Git工具 2.在C:\Documents and Settings\Administrator\目录下,运行Git Bash he ...

  2. git clone 指定分支 拉代码

    1.git clone 不指定分支 git clone http://10.1.1.11/service/tmall-service.git 2.git clone 指定分支 git clone -b ...

  3. go学习day3

    strings和strconv使用 1.strings.HasPrefix(s string, prefix string) bool:判断字符串s是否以prefix开头 2.strings.HasS ...

  4. python "爬虫+有道词典"实现一个简单翻译程序

    抓包软件使用的是Fiddler4 新版的查询接口 比较负责,引入了salt和sign http://fanyi.youdao.com/translate?smartresult=dict&sm ...

  5. java1.8新特性(optional 使用)

    经常在程序中出现 java.lang.NullPointerException  为了避免  报错,总是要进行一些 是否为null 的if else 判断 ,1.8 可以使用optional 类 来简 ...

  6. Spring Boot下Druid连接池+mybatis

      目前Spring Boot中默认支持的连接池有dbcp,dbcp2, hikari三种连接池.  引言: 在Spring Boot下默认提供了若干种可用的连接池,Druid来自于阿里系的一个开源连 ...

  7. 学习笔记之机器学习实战 (Machine Learning in Action)

    机器学习实战 (豆瓣) https://book.douban.com/subject/24703171/ 机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中 ...

  8. 廖雪峰Java5集合-1Java集合简介-1Java结合简介

    1.集合 定义:集合就是一堆东西.集合里的东西,称为元素Element 数学中的集合: 有限集合: * 一个班所有的学生组成的集合 * 一个网站所有的商品组成的集合 无限集合: * 全体自然数集合 * ...

  9. 3d图像坐标轴及css3属性的讲解

    3d立体坐标轴 如有不知道各种插件的怎么办? 网上查,百度 1.css选择器: 1.id 2.class 3.标签 4.子代 5.后代 6.交集 7.并级 8.通配符 9.结构 10.伪类 11.属性 ...

  10. [UE4]HorizontalBox,整体向右对齐