转载: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 ...
随机推荐
- pytest.1.快速开始
From: http://www.testclass.net/pytest/quick_start/ 简介 pytest测试框架可以让我们很方便的编写测试用例,这些用例写起来虽然简单,但仍然可以规模化 ...
- spring boot学习(8) SpringBoot 之切面AOP
在方法执行的前后,切入代码:经典的service层切入事务: @Aspect注解是切面注解类 @Pointcut切点定义 @Before是方法执行前调用 @After是方法执行后调用 @AfterRe ...
- java1.8 新特性(关于 match,find reduce )操作
match处理Integer集合 package lambda.stream; /** * @author 作者:cb * @version 创建时间:2019年1月4日 下午2:35:05 */ i ...
- 怎么把PNG图的位深度24位变成32位
在PS里把图片的变成层模式,不透明度设置成99%,在保存成PNG
- [转][C#]降级.net 源码4.5
来自:https://www.cnblogs.com/had37210/p/8057042.html 主要是 Task 的降级: 1.net4.5.2 引入了 async/await 关键字. 这个其 ...
- ping一个网段的cmd程序
ping一个网段的cmd程序 今天发现只在cmd命令行工具中输入: FOR /L %i IN (1,1,254) DO ping -n 1 192.168.1.%i 即可.
- vultr 上实现高可用冗余浮动公网IP出口(使用BIRD+BGP协议)High Availability on Vultr with Floating IP and BGP
官方文档: https://www.vultr.com/docs/high-availability-on-vultr-with-floating-ip-and-bgp https://www.vul ...
- [UE4]虚幻引擎UE4如何制作可拖动(Drag and Drop)的背包(Scrollbox)(转载)
最终效果 由于隐私保护,不想截实际的效果图,下面给出了示意图,左边是背包A,右边是背包B,将其中的子项目从左侧拖往右侧的背包,然后在插入位置放置. 第一步: 制作一个user widget(在内容浏览 ...
- Android 通过联系人姓名查询联系人号码
<!-- 读联系人权限 --><uses-permission android:name="android.permission.READ_CONTACTS" / ...
- gulp 使用案例
1.gulp 配置: // 引入 gulp var gulp = require('gulp'); var watch = require('gulp-watch'), //导入所有gulp需要的模块 ...