程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 用匯編的眼光看C++(之算術符重載陷阱)

用匯編的眼光看C++(之算術符重載陷阱)

編輯:C++入門知識

 

【 聲明:版權所有,歡迎轉載,請勿用於商業用途。  聯系信箱:feixiaoxing @163.com】

 

 

 

 

    在算術符重載裡面,“=”重載可能是最經常使用的一種。但是好多人就誤以為在函數中,凡是類出現“=”的地方,那就是調用算術符重載,其實不然。為什麼呢?我們可以看看下面的代碼。首先,我們定義一個基本類:

 

 

class data 

    char* value; 

    int number; 

public: 

    explicit data(int num = 0){ 

        if(num){ 

            number = num; 

            value = (char*)malloc(num); 

        } 

    } 

 

    data(const data& d){ 

        number = d.get_number(); 

        value = (char*)malloc(d.get_number()); 

        memmove(value, d.get_point(), d.get_number()); 

    } 

 

    ~data(){ 

        if(number) 

            free(value); 

    } 

 

    data& operator=(const data& d){ 

        if(number) 

            free(value); 

        number = d.get_number(); 

        value = (char*)malloc(d.get_number()); 

        memmove(value, d.get_point(), d.get_number()); 

        return *this; 

     

    } 

 

    int get_number() const {return number;} 

    char* get_point() const {return value;} 

}; 

class data

{

       char* value;

       int number;

public:

       explicit data(int num = 0){

              if(num){

                     number = num;

                     value = (char*)malloc(num);

              }

       }

 

       data(const data& d){

              number = d.get_number();

              value = (char*)malloc(d.get_number());

              memmove(value, d.get_point(), d.get_number());

       }

 

       ~data(){

              if(number)

                     free(value);

       }

 

       data& operator=(const data& d){

              if(number)

                     free(value);

              number = d.get_number();

              value = (char*)malloc(d.get_number());

              memmove(value, d.get_point(), d.get_number());

              return *this;

      

       }

 

       int get_number() const {return number;}

       char* get_point() const {return value;}

};

    定義好了函數之後,我們就開始對這個類進行調用,同樣代碼如下所示:

 

45:       data m(10); 

0040108D   push        0Ah 

0040108F   lea         ecx,[ebp-14h] 

00401092   call        @ILT+30(data::data) (00401023) 

00401097   mov         dword ptr [ebp-4],0 

46:       data p = m; 

0040109E   lea         eax,[ebp-14h] 

004010A1   push        eax 

004010A2   lea         ecx,[ebp-1Ch] 

004010A5   call        @ILT+35(data::data) (00401028) 

004010AA   mov         byte ptr [ebp-4],1 

47:       p = m; 

004010AE   lea         ecx,[ebp-14h] 

004010B1   push        ecx 

004010B2   lea         ecx,[ebp-1Ch] 

004010B5   call        @ILT+5(data::operator=) (0040100a) 

48:   } 

45:       data m(10);

0040108D   push        0Ah

0040108F   lea         ecx,[ebp-14h]

00401092   call        @ILT+30(data::data) (00401023)

00401097   mov         dword ptr [ebp-4],0

46:       data p = m;

0040109E   lea         eax,[ebp-14h]

004010A1   push        eax

004010A2   lea         ecx,[ebp-1Ch]

004010A5   call        @ILT+35(data::data) (00401028)

004010AA   mov         byte ptr [ebp-4],1

47:       p = m;

004010AE   lea         ecx,[ebp-14h]

004010B1   push        ecx

004010B2   lea         ecx,[ebp-1Ch]

004010B5   call        @ILT+5(data::operator=) (0040100a)

48:   }

    上面共有三句話,我們逐一進行分析:

 

    45句:定義了一個臨時變量,調用data的構造函數

 

    46句:出現了一個臨時變量p,這裡發現data類並沒有調用算術符重載函數,而是調用了data的構造函數,根據45句所示,調用的肯定不是普通的構造函數,那麼剩下的結果只能是拷貝構造函數

 

    47句: 和46句的代碼是一致的,但是此時調用的函數才是算術符重載函數

 

    所以說,出現“=”的地方未必調用的都是算術符重載函數,也有可能是拷貝構造函數。那麼什麼時候是拷貝構造函數,什麼時候是算術符重載函數呢?判斷的標准其實很簡單。如果臨時變量是第一次出現,那麼調用的只能是拷貝構造函數,反之如果變量已經存在,就像47句一樣,那麼調用的只能是算術符重載函數,但是我們這裡定義的算數符重載函數有一個陷阱,不知道大家看出來沒有?

 

    我提示大家一下,這裡的算術符重載需不需要判斷拷貝的是不是自己呢?

 

void process() 

    data m(10); 

    data p = m; 

    p = p; 

void process()

{

       data m(10);

       data p = m;

       p = p;

}    這裡最後一句,如果算術符可以自己拷貝給自己,代碼正常編譯和運行都沒有問題,但是在某些情況下會出現很多意想不到的情況。大家可以跟著我的思路來:

 

data& operator=(const data& d){ 

    if(this == &d)       /* check whether it is self-copy action */ 

        return *this; 

 

    if(number) 

        free(value); 

    number = d.get_number(); 

    value = (char*)malloc(d.get_number()); 

    memmove(value, d.get_point(), d.get_number()); 

    return *this; 

 

       data& operator=(const data& d){

              if(this == &d)       /* check whether it is self-copy action */

                     return *this;

 

              if(number)

                     free(value);

              number = d.get_number();

              value = (char*)malloc(d.get_number());

              memmove(value, d.get_point(), d.get_number());

              return *this;

      

       }

    如果上面的代碼沒有判斷復制的對象是不是自己,那麼我們發現實際上value的數據實際上已經free掉了。那麼此時重新分配內存,拷貝的數據只有天知道是什麼數據。原來value指向的內存空間就存在了很大的不確定性,這就是算術符重載的陷阱。

 

 

 

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