转载:C++函数中new一块内存,作为返回值
转载来自: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一块内存,作为返回值的更多相关文章
- (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAAE0CAIAAAB7LwoKAAAgAElEQVR4nO2dy6sc152A6+/R2mXwSn ...
- Ajax - 在函数中使用Ajax怎么使用返回值 - Ajax赋值给全局变量异常的解决方法
要使用异步操作: async : false,//取消异步操作 //添加节点函数 function InsertNode(nodenum, nodename, type) { var returnv ...
- 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存
申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...
- Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值
Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...
- c#中命令copy已退出,返回值为1
c#中命令copy已退出,返回值为1 本正经的道:董姐刚才你说的修心养性其中的'修心'我 有孕在身刚好由戴梦瑶顶替了她的位置按照的指示 ╋旆呆 湎术葶页 邾箕砜笳 烦璜卿廑 奶奶个腿儿的等下次非让你 ...
- ascii#ascii,对象类中找__repr__,获取其返回值
#!/usr/bin/env python #ascii,对象类中找__repr__,获取其返回值 class Foo : def __repr__(self): return "hello ...
- Python--day10(函数(使用、分类、返回值))
1. 函数 1. 函数: 完成特定功能的代码块,作为一个整体,对其进行特定的命名,该名字就代表这函数 现实中:很多问题要通过一些工具进行处理 => 可以将工具提前生产出来并命名 =>通 ...
- Python3学习之路~3.1 函数基本语法及特性、返回值、参数、局部与全局变量
1 函数基本语法及特性 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 语法定义: d ...
- Golang中defer、return、返回值之间执行顺序的坑
原文链接:https://studygolang.com/articles/4809 Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多go ...
随机推荐
- 黄聪:移动应用抓包调试利器Charles
一.Charles是什么? Charles是在 Mac或Windows下常用的http协议网络包截取工具,是一款屌的不行的抓包工具,在平常的测试与调式过程中,掌握此工具就基本可以不用其他抓包工具了 ...
- Android WebView 开发详解
Android WebView 开发详解 参见 http://blog.csdn.net/typename/article/details/39030091
- http系列(一)
一.关于Url URI由URL和URN组成,URI即统一资源标识符,URL即统一资源定位符,URN即统一资源名称. 现在最常用的是URL. 二.http请求/响应报文 请求报文:请求行.请求头部.空行 ...
- 记一次包含iframe的需要滚动的元素不能滚动到底部的问题
一个包含上头部.下部模块(包含左右两边模块:侧边栏.内容区域)的页面 前提条件,内容区域: 1.元素高度需要自适应屏幕高度 2.里面内容足够长时,可以滚动 3.包含了一个iframe嵌入的内容很长的页 ...
- PAT 乙级 1063 计算谱半径(20) C++版
1063. 计算谱半径(20) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 在数学中,矩阵的“谱半径”是指其特 ...
- Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素
ylbtech-Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素 1.返回顶部 1. Java 实例 - 删除数组元素 Java 实例 以下实例演示了如何使用 ...
- [转][C#]HttpClient 代码示例
转自:https://www.cnblogs.com/amosli/p/3918538.html 也参考了:https://www.cnblogs.com/ShadowFiend007/p/80668 ...
- linux安装tomcat9
0:环境准备 : 安装tomcat需要先配置jdk,所以没有配置jdk同学,先移步Linux安装JDK 或者使用比较便捷的方法,就是apt-get或者yum安装openJDK,这样做的话,会帮 ...
- Jmeter(三十六)纵横并发、限制QPS
一.纵横并发 Jmeter设计并发事件,这应该是一项必备技能. 首先来看并发的概念. 通常在性能测试中会涉及到并发用户数的概念,有关并发用户数(系统用户数)的详解后续再记. (有关并发.并行的概念参考 ...
- [UE4]函数分组
函数分组相当于C#里面的“#region #end region”折叠注释