C++编程小心指针被delete两次
在C++类中,有时候会使用到传值调用(即使用对象实体做参数),当遇到这种情况,可要小心了!尤其是当你所传值的对象生命周期较长,而非临时对象(生命周期段)的时候。来看看下面的情况:
#include <iostream> using namespace std; class Text { private: char * str; public: Text(){str = new char[20]; ::memset(str,0,20); } void SetText(char * str) { strcpy(this->str,str); } char * GetText() const{return str;} ~Text() { cout << "~Text Destruction" << endl; delete [] str; cout << "~Text Over" << endl; } }; void Print(Text str) { cout << str.GetText() << endl; } int main() { Text t; t.SetText("abc"); Print(t); return 1; }
上面执行的结果是程序崩溃了。原因是:
Print(Text str)在对str进行复制构造的时候,没有进行深度拷贝;当 Print退出的时候,因为是临时对象(函数初始时构造),对str进行析构,此时还没有出现任何问题;但回到main,继而退出main 的时候,又对t进行析构,但此时t内的str中的内容已经被销毁。由于对一内存空间实施了两次销毁,于是就出现了内存出错。
解决方法如下:
重写前拷贝。像以下版本,不同的情况要作出适当的调整:
#include <iostream> using namespace std; class Text { private: char * str; public: Text(){str = new char[20];::memset(str,0,20);} Text(Text &t) { str = new char[20]; strcpy(str,t.GetText()); } void SetText(char * str) { strcpy(this->str,str); } char * GetText() const{return str;} ~Text() { cout << "~Text Destruction" << endl; delete [] str; cout << "~Text Over" << endl; } }; void Print(Text str) { cout << str.GetText() << endl; } int main() { Text t; t.SetText("abc"); Print(t); return 1; }
此处推荐不使用传值调用。就像下面书写如下Print版本:
void Print(Text &str) { cout << str.GetText() << endl; }
除非对象内所有的成员读属非指针内存内容,那么谨慎使用文章前面提到的用法。
相关推荐
-
C++ new/delete相关知识点详细解析
每个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap).C语言用一堆标准库函数malloc和free在自由存储区中分配存储空间,而C++则用new和delete表达式实现相同的功能. 一.new和delete创建和释放动态数组:数组类型的变量有三个重要的限制:数组长度固定,在编译时必须知道其长度,数组只在定义它的语句内存在.动态数组:长度固定,编译时不必知道其长度,通常是运行时确定:一直存在,直到程序显示释放它.
-
C++中delete和delete[]的区别
一直对C++中的delete和delete[]的区别不甚了解,今天遇到了,上网查了一下,得出了结论.做个备份,以免丢失. C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]. 关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间:(2) 为自定义类型分配和回收空间. 请看下面的程序. #include <iostream>; using namesp
-
浅析c++中new和delete的用法
new和delete运算符用于动态分配和撤销内存的运算符 new用法: 1.开辟单变量地址空间1)new int; //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a. 2)int *a = new int(5) 作用同上,但是同时将整数赋值为5 2. 开辟数组空间一维: int *a = new int[100];开辟一个大小为100的整型数组空间二维: int **a = new int[5][6]三维
-
C++中delete和delete[]的区别说明
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]. 关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间:(2) 为自定义类型分配和回收空间. 请看下面的程序. 复制代码 代码如下: #include <iostream>;using namespace std; class T {public: T() { cout << &quo
-
C++ new、delete(new[]、delete[])操作符重载需要注意的问题
new.delete(new[].delete[])操作符的重载需要注意: 1.重载的 new.delete(或者 new[].delete[])操作符必须是类的静态成员函数(为什么必须是静态成员函数,这很好理解,因为 new 操作符被调用的时候,对象还未构建)或者是全局函数,函数的原型如下: 复制代码 代码如下: void* operator new(size_t size) throw(std::bad_alloc); // 这里的 size 为分配的内存的总大小 void* operato
-
c++中new和delete操作符用法
"new"是C++的一个关键字,同时也是操作符.当我们使用关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间.调用构造函数.返回正确的指针.当然,如果我们创建的是简单类型的变量,第二步就会被省略. new用法: 1. 开辟单变量地址空间 1)new int; 开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a. 2)int *a = new int(5) 作用同上,但是同时将整数
-
C++基础入门教程(五):new和delete
对于以前没有接触过C++,然后初次接触Cocos2d-x的朋友来说,可能对于内存管理方面会比较生疏. 也经常会因为内存问题导致各种小Bug,我也曾经写过一篇retain和release倒底怎么玩?,用来驾驭Cocos2d-x的对象引用和释放也算是足够了. 但,难道大家就不想知道retain和release背后的秘密吗?(小若:不想.) 没错,今天木头来带大家走进科学,走进世界,一起来探讨C++的new和delete.(小若:没兴趣.) 好,既然大家都等不及了,那就开始吧~ 1.动态分配内
-
C++编程小心指针被delete两次
在C++类中,有时候会使用到传值调用(即使用对象实体做参数),当遇到这种情况,可要小心了!尤其是当你所传值的对象生命周期较长,而非临时对象(生命周期段)的时候.来看看下面的情况: #include <iostream> using namespace std; class Text { private: char * str; public: Text(){str = new char[20]; ::memset(str,0,20); } void SetText(char * str) {
-
Java编程求二叉树的镜像两种方法介绍
给出一棵二叉树,求它的镜像,如下图:右边是二叉树是左边二叉树的镜像. 仔细分析这两棵树的特点,看看能不能总结出求镜像的步骤.这两棵树的根节点相同,但他们的左右两个子节点交换了位置.因此我们不妨先在树中交换根节点的两个子节点,就得到了下面一幅图中的第二颗树 解法1(递归) 思路1:如果当前节点为空,返回,否则交换该节点的左右节点,递归的对其左右节点进行交换处理. /*class TreeNode{ int val; TreeNode left=null; TreeNode right=null;
-
java编程实现杨辉三角两种输出结果实例代码
首先展示下结果: 简介: 杨辉三角,是二项式系数在三角形中的一种几何排列.在欧洲,这个表叫做帕斯卡三角形.帕斯卡(1623----1662)是在1654年发现这一规律的,比杨辉要迟393年,比贾宪迟600年.杨辉三角是中国古代数学的杰出研究成果之一,它把二项式系数图形化,把组合数内在的一些代数性质直观地从图形中体现出来,是一种离散型的数与形的优美结合. 实例代码如下: package com.sxt; import java.util.Arrays; public class KeBen { p
-
React编程中需要注意的两个错误
前言 在React编程中, 我们习惯用useEffect.useState等Hook去进行开发,但是在开发过程中难免会遇到许多问题,前阵子,我在写代码的时候,踩过不少坑,这里先列举两个较为常见的,也希望读者们看完这篇文章能够避免踩坑! 一. useEffect无限渲染 背景: 页面初始化的时候,我们需要通过useEffect()来进行一些初始化工作. 在useEffect()方法中,调用了代码getData()去后台调取数据. 比如页面所需的userName字段,我们在获取数据后,调用setUs
-
C++编程中指针的声明与基本使用讲解
使用以下序列声明指针. [storage-class-specifiers] [cv-qualifiers] type-specifiers [ms-modifier] declarator ; 其中,任何有效指针声明符均可用于 declarator.简单指针声明符的语法如下所示: * [cv-qualifiers] identifier [= expression] 1.声明说明符: 可选存储类说明符. 应用于要指向的对象的类型的可选 const 或 volatile 关键字. 类型说明符:可
-
讲解C语言编程中指针赋值的入门实例
从const int i 说起 你知道我们声明一个变量时象这样int i :这个i是可能在它处重新变赋值的.如下: int i = 0; /* . . . */ i = 20; /*这里重新赋值了*/ 不过有一天我的程序可能需要这样一个变量(暂且称它变量),在声明时就赋一个初始值.之后我的程序在其它任何处都不会再去重新对它赋值.那我又应该怎么办呢?用const . /* . . . */ const int ic =20; /* . . . */ ic = 40; /*这样是不可以的,编译时是无
-
剖析C++编程当中指针作为函数参数的用法
在C语言中,函数指针变量常见的用途之一是作为函数的参数,将函数名传给其他函数的形参.这样就可以在调用一个函数的过程中根据给定的不同实参调用不同的函数. 例如,利用这种方法可以编写一个求定积分的通用函数,用它分别求5个函数的定积分: 可以看出,每次需要求定积分的函数是不一样的.可以编写一个求定积分的通用函数integral,它有3个形参: 下限a.上限b,以及指向函数的指针变量fun.函数原型可写为: double integral (double a, double b, double (*fu
-
C语言编程函数指针入门精讲教程
目录 一.指针引子 二.使用步骤 1.取函数地址 2.创建函数指针 3.通过函数指针调用函数的两种方法 三.函数指针进阶 总结 一.指针引子 示例:我们常常接触的指针大多有如下几类: 整形指针-存放整形地址,指向整形 字符指针-存放字符地址,指向字符 数组指针-存放数组地址(注意不是数组首元素地址),指向数组 由以上三个例子,我们能总结指针的共同点:存放某个类型变量的地址,指向那个类型的变量,但是在讲函数指针首先有一个问题:函数也有地址吗?我们用一段简单的代码来验证一下即可. #include<
-
智能指针与弱引用详解
在android 中可以广泛看到的template<typename T> class Sp 句柄类实际上是android 为实现垃圾回收机制的智能指针.智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数,所以为了实现内存( 动态存储区) 的安全回收,必须对指针进行一层封装,而这个封装就是智能指针,其实说白了,智能指针就是具备指针功能同时提供安全内存回收的一个类.当然,智能指针的功能还不只这些,想了解更多大家可以去研究下- 智能指针有很多实现
-
C++ 使用new与delete需注意的原则
C++的动态内存管理是通过new和delete两个操作来完成的,即用new来申请空间,用delete来释放空间.在使用new和delete时,注意以下原则. 1.new与delete需一一对应 用new操作申请空间,如果申请成功,必须在以后的某个时刻用delete释放该空间,既不能忘记释放,也不能多次释放.前者会引起内存泄露,后者会引起运行时错误.如下面的程序. #include <iostream> using namespace std; int main() { int *p; p=ne
随机推荐
- asp.net SqlDataReader绑定Repeater
- JavaScript高级程序设计 事件学习笔记
- 站长必备的最齐全的301转向代码合集
- Centos下安装docker教程
- 解析iOS内存不足时的警告以及处理过程
- JavaScript基础——使用Canvas绘图
- asp.net 抓取网页源码三种实现方法
- django1.8使用表单上传文件的实现方法
- Android中利用zxing实现自己的二维码扫描识别详解
- 浅谈使用splice函数对数组中的元素进行删除时的注意事项
- csh脚本语法实例
- C#无损高质量压缩图片实现代码
- 数据库删除完全重复和部分关键字段重复的记录
- Mongodb常见错误与解决方法小结(Mongodb中经常出现的错误)
- jQuery+CSS3折叠卡片式下拉列表框实现效果
- 20个非常棒的Jquery实用工具 国外文章
- javascript 验证码生成代码 推荐学习
- C#函数式编程中的标准高阶函数详解
- javascript asp教程添加和修改
- python使用RNN实现文本分类