程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 關於“非基本類型需慎用memcpy函數”的分析

關於“非基本類型需慎用memcpy函數”的分析

編輯:關於C

 

假設我們要將一個元素類型為T的對象數組復制到另外一個數組中,我可以很輕松寫出如下代碼

 

T sour[N]; 

T dest[N]; 

int i; 

for(i = 0; i < N; i++) 

    dest[i] = sour[i]; 

在C和C++中,上述代碼都可以生效

然而,C程序員可能更喜歡用下面的方案

 

T sour[N]; 

T dest[N]; 

int i; 

memcpy(dest, sour, N*sizeof(T)); 

這種做法在C中能很好的工作,然而如果T是非基本類型,上述代碼在C++中就有可能會帶來災難,因為memcpy是按位拷貝,這涉及到深拷貝和淺拷貝的問題

 

如果類型T具有下面的特征,則不能對其使用memcpy

1.類型T需要顯式定義復制構造函數和賦值操作符

2.類型T不需要顯式定義復制構造函數和賦值操作符,但其底層數據成員需要顯式定義復制構造函數和賦值操作符

參照下列代碼

 

#include <iostream> 

#include <string> 

using namespace std; 

//不能對B使用memcpy函數的原因是顯而易見的 

class B 

public: 

    int *a; 

    B(int m = 0) 

    { 

        cout << "B的構造函數" << endl; 

        a = new int; 

        *a = m; 

    } 

    B(const B& b) 

    { 

        cout << "B的復制構造函數" << endl; 

        a = new int; 

        *a = *(b.a); 

    } 

    B& operator=(const B& b) 

    { 

        cout << "調用B的賦值操作符" << endl;  

        if(&b != this) 

        { 

            delete a; 

            a = new int; 

            *a = *(b.a); 

        } 

        return *this; 

    } 

    ~B() 

    { 

        cout << "調用B的析構函數" << endl; 

        delete a; 

    } 

 

}; 

//A不需要定義復制構造函數、賦值操作符、析構操作符,但也不能對A使用mencpy函數 

class A 

public: 

    B b; 

    A(int m = 0) : b(m) {} 

}; 

void main() 

{  

    A a1(1); 

    A a2(2); 

 

    cout << "測試A是否需要賦值操作符" << endl; 

    cout << "a1: " << a1.b.a << " " << *(a1.b.a) << endl; 

    cout << "a2: " << a2.b.a << " " << *(a2.b.a) << endl; 

    a1 = a2; 

    //memcpy(&a1,&a2,sizeof(A));//注意萬萬不可對A調用memcpy這種按位拷貝函數 

    cout << "a1: " << a1.b.a << " " << *(a1.b.a) << endl; 

    cout << "a2: " << a2.b.a << " " << *(a2.b.a) << endl;  

     

    cout << "測試A是否復制構造函數" << endl; 

    A a3(1); 

    cout << "a3: " << a3.b.a << " " << *(a3.b.a) << endl; 

    A a4(a3); 

    cout << "a4: " << a4.b.a << " " << *(a4.b.a) << endl; 

運行結果

B的構造函數

B的構造函數

測試A是否需要賦值

a1: 00036208 1

a2: 00036238 2

調用B的賦值操作符

a1: 00036208 2

a2: 00036238 2

測試A是否復制構造

B的構造函數

a3: 000362E0 1

B的復制構造函數

a4: 00036310 1

調用B的析構函數

調用B的析構函數

調用B的析構函數

調用B的析構函數

 

注:默認的賦值操作符和復制構造函數遞歸的依賴於底層類的成員的復制和賦值的定義,它不僅僅像C版本的結構體那樣僅實施按位復制,它只向內建類型成員變量實施按位復制,默認的析構函數也遞歸的依賴於底層類的析構函數

 

摘自 yucan1001

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved