歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

淺析:淺拷貝 及 深拷貝的傳統寫法

淺拷貝會造成指針懸掛的問題。

 舉個例子:兩個對象是s1和s2的指針_str都指向new開辟的同一塊空間,如下圖,主程序結束時,對象逐個撤銷,先撤銷對象s2,會調用析構函數釋放動態分配的內存;再撤銷對象s1時,s1._str所指向的內存空間已經是無法訪問了,而s2._str原先指向的那塊內存卻無法釋放,出現了所謂的指針懸掛! 兩個對象企圖釋放同一塊內存,從而導致一塊內存被釋放兩次這也是不行的,運行會出錯。

#include <iostream>
using namespace std;

class String
{
public:
          String(char *str)
                    :_str(new char [strlen(str )+1])
          {
                              strcpy(_str, str);
          }
          String(const String & s)
          {
                    _str = s._str;
          }
          String& operator=(const String & s )
          {
                    if (this !=&s)
                    {
                              _str = s._str;
                    }
                    return *this ;
          }
          ~String()
          {
                    delete[] _str;
          }
private:
          char* _str;
};

void Test()
{
          String s1("Lynn" );
          String s2=s1;
}
int main()
{
          Test();
          system("pause" );
          return 0;
}

深拷貝  深拷貝解決了指針懸掛的問題,當調用拷貝構造或賦值運算符的重載函數時,程序會生成一份該內存的拷貝,這樣每個指針都會指向一塊相對獨立的空間,撤銷對象時調用析構函數,分別釋放他們自己的動態分配的內存,相互之間不影響。如下圖:

深拷貝
///////////////////////////////////////////////////////////////////////////////////////
 
//          寫String類的構造函數時一定要注意參數問題
//          首先要考慮到構造的對象分有參數和無參數兩種情況
//          構造對象的時候不能直接賦值,否則一塊內存兩次釋放的話程序會出錯
//          無參的構造函數不能將_str指針賦值為NULL,因為不能strlen(NULL)
//          賦值運算符的重載要考慮到有可能分配內存失敗的問題
//          當然,記得要給'\0'分配空間哦
//                                                                    By:Lynn-Zhang
//////////////////////////*****************////////////////////////////////////////////
 
#include<iostream>
using namespace std;
 
class String
{
public:
           
          String(char * str="")          //不能strlen(NULL)
                    :_str(new char [strlen(str ) + 1])
          {
                    strcpy(_str, str);
          }
          String(const String &s)
                    :_str(new char [strlen(s ._str) + 1])
          {
                    strcpy(_str, s._str);
          }
           
          //賦值運算符的重載
          String& operator=(const String& s)
          {
                    if (this != &s )
                    {
                        /*    //有可能開辟空間失敗,但是卻破壞了_str的內容
                              delete[] _str;
                              _str = new char[strlen(s._str) + 1];
                              strcpy(_str, s._str);  */
 
                              char* tmp = new char [strlen(s ._str) + 1];
                              strcpy(tmp, s._str);
                              delete[] _str;
                              swap(_str, tmp);
 
                    }
                    return *this ;
          }
          char* CStr()
          {
                    return _str;
          }
          ~String()
          {
                    delete[] _str;
          }
private:
          char* _str;
};
 
 
//函數測試
void Test()
{
          String s1("aaaaa" );
          cout << s1.CStr() << endl;
          String s2(s1);
          cout << s2.CStr() << endl;
          String s3 = s1;
          s3= s2;
          cout << s3.CStr() << endl;
          String s4;
          // s4 = s1;
          cout << s4.CStr() << endl;
         
}
int main()
{
          Test();
          system("pause" );
          return 0;
}

Copyright © Linux教程網 All Rights Reserved