zoukankan      html  css  js  c++  java
  • 小心指针被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中的内容已经被销毁。由于对一内存空间实施了两次销毁,于是出现内存出错。

    解决方法:

      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. 除非对象内所有的成员读属非指针内存内容,那么谨慎使用文章前面的用法。
  • 相关阅读:
    thinkphp的钩子的两种配置和两种调用方法
    php闭包实现函数的自调用,也是递归
    php的spl_autoload_register函数的一点个人见解
    详解js变量、作用域及内存
    关于js的call()和apply()两个函数的一点个人看法
    php实现斐波那契数列以及由此引起的联想
    php猴子称王或者约瑟夫难题
    Linux Bash Shell 快速入门
    Fedora14下首次搭建Samba服务器遇到的一些问题
    【JavaScript】我的JavaScript技术总结第一篇——编程细节
  • 原文地址:https://www.cnblogs.com/candl/p/3813293.html
Copyright © 2011-2022 走看看