转载自:http://blog.csdn.net/jxluofeng/article/details/19766801

《问题》危险的代码:

int* p=new int(1);
   delete p;
   delete p;

探讨一:

连续两次对同一个指针delete ,会造成严重的错误。编译器会检测出这样的错误吗?或许一些编译器会的,但别太过指望编译器。

探讨二:

第一次delete后,p自动为空(NULL)了吗?不是的。

探讨三:

在delete之前会自动检查p是否为空(NULL),如果为空(NULL)就不再delete了吗?确实是如此。

探讨四:

删除为空(NULL)的指针是不会有任何问题的吗?确实是如此。

探讨五:

#define SAFE_DELETE(p) delete (p); p = 0;

这样就就万事大吉了吗?好像不是的。

delete p+1;//在C++中是正确的

SAFE_DELETE(p+1)将会导致错误

探讨六:

没有好的方法解决重复释放这样的问题,只能靠程序员的细心了。

《结论》安全的代码:

int* p=new int(1);
   delete p;
   p = NULL;

(1)delete 一次以后,p成了野指针,它作为地址的值还是有效地没还可以访问它以前指向的内存,不过那片内存被重新格式化了;
(2)p不等于NULL,用 if(p) 语句不能判断它指向的内存是否有效(此时它指向的内存无效,p本身有效);
(3)delete 一次以后,不能再次delete,否则会报错;
(4)此时如果误用p指针,仍然可以修改内存的值和从该处取出数值,但此时数据不受保护,该内存空间可能被重新被分配给别的变量;
(5)如果p指向的空间再次被new函数分配,即使是分配给别的指针,即使分配大小与原来不一样,p又恢复了效力,可以改变内存的值,甚至可以重新被delete,p的作用与新分配的指针一样;

转载自: C++ 一不小心被delete两次

2012-09-11 12:10 by 捣乱小子, 2720 阅读, 31 评论, 收藏编辑

2012-09-11 18:04:看到园里朋友们这么热心,有那么一会心里好兴奋。:)

2012-09-11 下午:本文曾出现很严重的错误,但不要紧,感谢园友们的即使指正。

不喜欢程序语言的

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中的内容已经被销毁。由于对一内存空间实施了两次销毁,于是出现内存出错。

解决方法:

  1. 重写浅拷贝。像一下版本,不同的情况要作出适当的调整:

    #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;
    }
  2. (推荐)不使用传值调用。就像下面书写如下Print版本: 
    void Print(Text &str)
    {
        cout << str.GetText() << endl;
    }
  3. 评论中的小伙伴还提供了一个方法,很值得推荐,同时这也是编程良好的习惯:指针在使用的时候需要作空判断,在删除指针时候需要置空。

后记——语言的探讨

C++,以至于其他的程序语言,都是伟大的创造。他们是规则的世界,一愣一脚皆规则。当对某一规则有所熟知之后,就似发现新大陆似的。但想想,这些规则可经不起碰撞打击,殃及的是coder,是我们。这些规则不像1+1=2,“三点定面”来的铁定,总之比起数学理论来说,似乎程序规则脆弱很多,总之在它们身上看到的价值是有限的,总我还是选择了计算机...为之奈何,不得而知。

C++ delete 两次的更多相关文章

  1. 小心指针被delete两次

    C++类中,有时候使用到传值调用(对象实体做参数),遇到这种情况,可要小心了!特别是当你所传值的对象生命周期较长,而非临时对象(生命周期段)的时候.来看看下面的情况: #include <ios ...

  2. mysql delete两种关联删除方式

    基本格式:  DELETE t1 FROM t1,t2 WHERE t1.id=t2.id 或 DELETE FROM t1 USING t1,t2 WHERE t1.id=t2.id  示例应用: ...

  3. 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。

    (1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...

  4. delete和delete[]

    c++中对new申请的内存的释放方式有delete和delete[两种方式,到底这两者有什么区别呢? 1.我们通常从教科书上看到这样的说明:delete 释放new分配的单个对象指针指向的内存dele ...

  5. 为什么使用enable_shared_from_this——shared_ptr两类错误

    在使用C++实现弱回调时,订阅者应当维护一系列发布者的weak_ptr,而发布者注册回调时要传出this的shared_ptr指针,流行的实现方法是使用std::enable_shared_from_ ...

  6. delete 和 delete [] 的真正区别

    c++中对new申请的内存的释放方式有delete和delete[两种方式,到底这两者有什么区别呢? 1.我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指向的内存 de ...

  7. 关于delete和delete[]的区别

    在C++动态内存分配中我们常用到new和delete两种操作,new用来申请内存,delete用来释放内存.那么问题来了,我们应该用delete来释放内存还是用delete[]来释放内存呢? 为了得到 ...

  8. 转 delete 和 delete []的真正区别

    c++中对new申请的内存的释放方式有delete和delete[两种方式,到底这两者有什么区别呢? 1.我们通常从教科书上看到这样的说明:delete 释放new分配的单个对象指针指向的内存dele ...

  9. delete释放空间时出错的原因

    int *a=new int[10]; ...... delete []a; 后面“delete []a;”出现错误的情况大致有: 1 数组的首地址a被你有意无意更改了,如:a++之类的: 2 变量的 ...

随机推荐

  1. 最短路径之迪杰斯特拉算法(Java)

    1)Dijkstra算法适用于求图中两节点之间最短路径 2)Dijkstra算法设计比较巧妙的是:在求源节点到终结点自底向上的过程中,源节点到某一节点之间最短路径的确定上(这也是我之前苦于没有解决的地 ...

  2. 笔记--tslib 编译

    tslib 是qt启动时的一个触屏校正检验程序. 它的配置以及编译比较简单. 第一步, 下载tslib源码包: http://download.csdn.net/detail/MKNDG/329156 ...

  3. TI C6000 数据存储处理与性能优化

    存储器之于CPU好比仓库之于车间.车间加工过程中的原材料.半成品.成品等均需入出仓库,生产效率再快,如果仓库周转不善,也必然造成生产阻塞.如同仓库需要合理地规划管理一般,数据存储也需要恰当的处理技巧来 ...

  4. js按钮点击事件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 2 js的20/80关键知识

    1. 2 var a = 1; undefined a 1 alert(a); undefined var b = true; var c = "Hi"; undefined al ...

  6. 冒泡排序&快速排序

    1.排序分为以下四类共七种排序方法: 交换排序: 1) 冒泡排序  2) 快速排序 选择排序: 3) 直接选择排序  4) 堆排序 插入排序: 5) 直接插入排序  6) 希尔排序 合并排序: 7) ...

  7. 《Cracking the Coding Interview》——第12章:测试——题目5·

    2014-04-25 00:41 题目:怎么测试一支笔?(Pen?您老说的是钢笔?) 解法:这种简约而不简单的题目,实在是面试官最喜欢,面试者最头疼的类型了.面试官可以只花三秒,以一种灰常高贵冷艳的语 ...

  8. PoolManager

    我用的PoolManager版本是5.5.2的,导入的包总共有三个文件夹:Editor,Plugins,PoolManagerExampleFiles 1.Editor这个文件夹里面的东西,顾名思义, ...

  9. hnust 原石法阵

    问题 F: 原石法阵 时间限制: 1 Sec  内存限制: 128 MB提交: 1098  解决: 161[提交][状态][讨论版] 题目描述 WZH有一个由原石构成的n阶三角形魔法阵,三角形魔法阵如 ...

  10. 用Python实现基于Hadoop Stream的mapreduce任务

    用Python实现基于Hadoop Stream的mapreduce任务 因为Hadoop Stream的存在,使得任何支持读写标准数据流的编程语言实现map和reduce操作成为了可能. 为了方便测 ...