天天看點

面試知識點總結——深淺拷貝

  1. 差別
    • 在未定義顯示拷貝構造函數的情況下,系統會調用預設的拷貝函數——即淺拷貝,它能夠完成成員的一對一拷貝(逐位複制),當類中資料成員沒有指針時,利用淺拷貝完全沒有問題;但當資料成員中有指針時,如果采用簡單的淺拷貝,那麼兩個類中的兩個指針将會指向同一塊位址,當對象快結束時,會調用兩次析構器,進而導緻指針懸挂現象,是以此時必須使用深拷貝
    • 簡單來說,帶指針用深拷貝,不帶指針用淺拷貝
  2. 具體解釋
    • 無指針的淺拷貝

      x ———-> x

      p ———-> p

    • 有指針的淺拷貝

      x ———–> x

      *p ———–> *p

      \ /

      ​ \ /

      ​ \ /

      ​ 記憶體

    • 有指針的深拷貝

      x ————> x

      *p ————> *p

      | |

      | |

      記憶體 記憶體

  3. 用代碼解釋深淺拷貝
    • 無指針的淺拷貝
      class A
      {
       public:
          A(int _data):data(_data){}
          A(){}
       private:
          int data;
      };
      
      int main()
      {
       A a();
       A b = a; //淺拷貝
      }
      //解釋:b = a;就是淺拷貝,執行完b.data = 5;如果對象中沒有其他資源(如:堆,檔案,系統資源),則深淺無差。
                 
    • 有指針的淺拷貝(導緻記憶體洩漏)
      class A
      {
       public:
          A(int _size):size(_size)
           {
               data = new int[size];
           }//給data配置設定size個記憶體
          A(){}
          ~A()
           {
               delete []data;
           }
       private:
          int *data;
          int size;
      };
      
      int main()
      {
       A a();
       A b = a;
      }
      //這裡b = a會造成未定義行為,因為類A中拷貝構造器是編譯器生成的,是以b=a執行的是淺拷貝。
      //這裡b的指針data和a的指針指向了堆上的同一塊記憶體,a和b析構時同一塊記憶體将會被釋放兩次其結果是,有未定義的記憶體将會被洩漏或程式崩潰
                 
    • 有指針的深拷貝
      class A
      {
       public:
          A(int _size):size(_size)
           {
               data = new int[size];
           }//給data配置設定size個記憶體
          A(){}
          A(const A&_A):size(_A.size)
           {
               data = new int[size];
           }//深拷貝
          ~A()
           {
               delete []data;
           }
       private:
          int *data;
          int size;
      };
      
      int main()
      {
       A a();
       A b = a;
      }
                 

繼續閱讀