<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-204  評論-149  文章-0  trackbacks-0

    Sales_item operator+(const Sales_item& lhs,const Sales_item& rhs)
    {
        Sales_item ret(lhs) ;
        ret+= rhs ;
        return ret ;
    }
    怎么可以返回一個局部變量呢??????
    例如
    Sales_item item1,item2,item3 ;
    ......(item2,item3初始化成員變量)
    item1 = item2 + item3 ;


    沒有問題,它返回的是一個值,而不是引用,所以是正確的。在item1 = item2 + item3 中發生了一次值拷貝(賦值),也就是將item2+item3返回的局部變量拷貝給了item1之后,局部變量的作用域結束 
     
    可以返回局部變量,但是不能返回局部變量的引用。理解區分值和引用這兩個概念是學習C++的一大關鍵,明白這兩個概念之后,你就會理解為什么C++的類里面需要有拷貝構造函數,賦值操作符,析構函數三個元素了以及其它的一些稀里古怪的用法和忠告了
    --

     

    Sales_item operator+(const Sales_item& lhs,const Sales_item& rhs) 

        Sales_item ret(lhs) ; 
        ret+= rhs ; 
        return ret ; 
    }
    在return ret 時并不是簡單的返回這個局部變量,而是返回的是ret的一個副本temp,
    temp是通過拷貝構造函數實現的 即 Sales_item temp(ret);也就是說在主函數中用的其實是個temp,而ret早在operator+調用完畢后就釋放了,而temp這個 對象一直在主函數中貯存(雖然顯示是看不到的 )  ????


    嗯嗯,臨時對象一直是個有爭議的話題。temp只是臨時構造的,在賦值完畢之后它就析構了,不是一直在主函數中貯存的。這個臨時對象的作用域是什么???
    在你提的這種情況下,其實編譯器是可以優化掉這個副本的,但是可惜C++標準只允許優化  “Sales_item item1=item2+item3” 這種情況的,也就是在拷貝構造這種情況下,編譯器都不再產生副本,而賦值還是不行的。也許在未來的C++標準由可能通過拓展語義來消除臨時對象,畢竟臨時對象成為影響C++效率的一個主要因素。
    --

    ???
    目前的C++標準不允許在賦值的時候優化掉函數返回的副本,也就是下面這兩種情況是不一樣的
     
    //這是賦值給item1,目前的標準下是會產生副本 temp
    Sales_item item1,item2,item3;
    item1=item2+item3;
     
    //這是拷貝構造item1,編譯器通常會優化(這個優化區別下面所說的NRV優化)掉副本,也就是不產生副本 temp
    Sales_item item2,item3;
    Sales_item item1=item2+item3;

    看一下代碼中的TheFunctionTwo();

      1 #include<iostream>
      2 #include<string>
      3 
      4 using namespace std;
      5 

      6 class SimpleCat
      7 
    {
      8 public
    :
      9     SimpleCat(void
    );
     10     SimpleCat(int age,int
     weight);
     11     SimpleCat(SimpleCat &
    rsc);
     12     SimpleCat & operator=(const SimpleCat &
    rhs);
     13     int GetAge(){return
     itsAge;}
     14     int GetWeight(){return
     itsWeight;}
     15     void SetAge(int age){itsAge =
     age;}
     16 

     17 private:
     18     int
     itsAge;
     19     int
     itsWeight;
     20     //int itsAge=5;//1>.\SimpleCat.cpp(14) : error C2864: “SimpleCat::itsAge”: 只有靜態常量整型數據成員才可以在類中初始化

     21 
     22 public:
     23     virtual ~SimpleCat(void
    );
     24 
    };
     25 

     26 SimpleCat::SimpleCat(void)
     27 
    {
     28     cout<<"SimpleCat constructor "<<this<<
    endl;
     29 
    }
     30 

     31 SimpleCat::SimpleCat(int age,int weight)
     32 
    {
     33     cout<<"SimpleCat constructor "<<this<<
    endl;
     34     itsAge =
     age;
     35     itsWeight =
     weight;
     36 
    }
     37 

     38 SimpleCat::SimpleCat(SimpleCat &rhs)
     39 
    {
     40     cout<<"SimpleCat copy constructor"<<this<<" 從 "<<&rhs<<"拷貝"<<
    endl;
     41     itsAge =
     rhs.itsAge;
     42     itsWeight =
     rhs.itsWeight;
     43 
    }
     44 

     45 SimpleCat &SimpleCat::operator=(const SimpleCat &rhs)
     46 
    {
     47     cout<<"SimpleCat重載賦值運算符"<<this<<" 從 "<<&rhs<<"賦值"<<
    endl;
     48     itsAge =
     rhs.itsAge;
     49     itsWeight =
     rhs.itsWeight;
     50     return *this
    ;
     51 
    }
     52 

     53 SimpleCat::~SimpleCat(void)
     54 
    {
     55     cout<<"SimpleCat destructor"<<this<<
    endl;
     56 
    }
     57 

     58 SimpleCat &TheFunction();
     59 

     60 SimpleCat TheFunctionTwo();
     61 

     62 SimpleCat &TheFunctionThree();
     63 

     64 void TheFunctionFour(SimpleCat simpleCat);
     65 

     66 int main()
     67 
    {
     68 
        SimpleCat myCat;
     69     cout<<myCat.GetAge()<<endl;//
    這個值區別于java不是賦初值為0的,而是一個隨機的值
     70 //    cout<<myCat.itsAge<<endl;

     71 
     72     cout<<"------------------------"<<endl;
     73     SimpleCat &rCat =
     TheFunction();
     74     int age =
     rCat.GetAge();
     75     cout<<"rCat is "<<age<<"yeas old!"<<
    endl;
     76     cout<<"&rCat:  "<<&rCat<<
    endl;
     77     SimpleCat *pCat = &
    rCat;
     78     //delete rCat;//不能對引用使用delete

     79     delete pCat;
     80     //
    delete好像沒有釋放內存,怎么獲取的還是原來的值
     81     //可能在這個內存區域存放的還是原來的?先new string后再調用也沒變,與編譯器有關還是什么??

     82     for(int i =0;i<10;i++)
     83 
        {
     84         //想通過創建string對象來填充之前的內存區間,好像沒用

     85         string *= new string("abcdefghijklmn");
     86 
        }
     87 

     88     //這時問題來了,rCat.getAge()為123了
     89     SimpleCat *pSecond = new SimpleCat(123,444);
     90 
        
     91     cout<<"delete pCat后再使用rCat引用會發生什么問題???"<<
    endl;
     92     cout<<"delete pCat后 &rCat"<<&rCat<<
    endl;
     93     cout<<"delete pCat后 rCat.age"<<rCat.GetAge()<<
    endl;
     94 

     95     cout<<"--------------------------"<<endl;
     96     SimpleCat myCat2 = TheFunction();//
    這個會發生內存泄漏,在函數中申請的內存會得不到釋放
     97                                      //myCat2是通過默認的拷貝函數來進行初始化的

     98     cout<<"myCat2的地址是 "<<&myCat2<<endl;
     99     cout<<endl<<"---------------------------"<<
    endl;
    100 

    101     //直接的調用默認拷貝構造函數的
    102     //
    cout<<"直接的調用默認拷貝構造函數的,這個語句一共創建了多少個對象"<<endl;
    103     //SimpleCat myCat3 = TheFunctionTwo();//
    這個盡然沒調用拷貝構造函數?????
    104     //
    cout<<"myCat3的地址是 "<<&myCat3<<endl;
    105     //
    cout<<"myCat3.GetAge()  "<<myCat3.GetAge()<<endl;
    106 

    107     //調用默認的賦值運算符的
    108     //
    cout<<"調用默認的賦值運算符的,這個語句一共創建了多少個對象"<<endl;
    109     //
    SimpleCat myCat4;
    110     //
    myCat4 = TheFunctionTwo();
    111     //
    cout<<"myCat4.GetAge()  "<<myCat4.GetAge()<<endl;
    112 

    113 
    114     //這種調用的方式
    115     //
    cout<<"TheFunctionTwo()返回的臨時對象賦給一個引用"<<endl;
    116     //
    SimpleCat &rmyCat = TheFunctionTwo();
    117     //
    cout<<"打印一下返回的臨時對象的地址,臨時對象賦給引用之后就不會立即析構了---"<<&rmyCat<<endl;
    118     //cout<<"rmCat.GetAge() "<<rmyCat.GetAge()<<endl;

    119 
    120     SimpleCat myCat5;
    121 
        TheFunctionFour(myCat5);
    122 

    123     return 0;
    124 
    }
    125 

    126 
    127 //這個函數在返回時,是否會創建一個臨時引用變量???
    128 //
    TheFunctionTwo(SimpleCat &simpleCat)這個函數在傳遞參數時是否會創建一個臨時的引用變量
    129 //臨時的引用變量的作用域范圍是什么

    130 SimpleCat &TheFunction()
    131 
    {
    132     SimpleCat *pFrisky = new SimpleCat(5,9
    );
    133     cout<<"pFrisky: "<<pFrisky<<
    endl;
    134     return *
    pFrisky;
    135 
    }
    136 

    137 
    138 
    139 //我要看對象被創建了幾次,是否創建臨時對象
    140 SimpleCat TheFunctionTwo()
    141 
    {
    142 
        SimpleCat tempCat;
    143     cout<<"in TheFunctionTwo tempCat指針 "<<&tempCat<<
    endl;
    144     tempCat.SetAge(9999
    );
    145     //返回時是否還創建一個臨時對象

    146     return tempCat;
    147 

    148 }
    149 

    150 
    151 //這種方式肯定是錯的,返回了局部變量的引用
    152 SimpleCat &TheFunctionThree()
    153 
    {
    154     SimpleCat tempCat;//局部變量

    155     cout<<"in TheFunctionThree tempCat指針 "<<&tempCat<<endl;
    156     tempCat.SetAge(9999
    );
    157     //返回時是否還創建一個臨時對象,已引用的形式

    158     return tempCat;
    159 
    }
    160 

    161 
    162 
    163 //我要看再實參對形參進行拷貝構造時,是否會打印出調用的拷貝函數信息
    164 void TheFunctionFour(SimpleCat simpleCat)
    165 
    {
    166     cout<<"形式參數simpleCat的地址 "<<&simpleCat<<
    endl;
    167 

    168 }
    169 

    170 
    171 

    ------------------------------------------------------------------------------------------------------------------------------
    先說說第一塊吧,
    這個貌似應該調用拷貝構造的地方沒有調用拷貝構造,應該是編譯器做的優化,可以參考《深入探索C++對象模型》P66頁。
    按照書中的說法,很可能只創建了1個對象
     
    X bar()
    {
        X xx;
        return xx;
    }
    可能會被編譯器優化成
    void bar(X & _result)
    {
        _result.X::X();
        return;
    }
     
    所以調用X a = bar(),其實被轉換成 bar(X& a);
    所以一個本該調用拷貝構造的地方卻很可能調僅用了構造函數來完成工作。
    這個問題我也沒有搞明白,我沒有試過lz的代碼是不是會這樣,如果真這樣的話,我覺得編譯器就管的太多了,如果拷貝構造中有一些特殊的功能呢(就像樓主有個輸出語句),豈不是無聲無息中被抹殺了。這個功能被稱為NRV,好像一直沒有人對這個問題給出非常明確的回答
    ------------------------------------------------------------------------------------------------------------------------------
    thx,在vs2005中代碼優化開啟時,第一塊確實只會調一個構造函數
    把代碼優化禁用后,就會調用拷貝構造函數了
    確實是個NRV的問題
    http://blog.vckbase.com/bruceteen/archive/2005/12/30/16652.html
    ------------------------------------------------------------------------------------------------------------------------------

    正如4樓的所說~~~
    到底創建多少臨時對象,要視編譯器而定,看編譯器是否采用NVR...
    (其實一般情況下,NVR都是未采用的~),因此對后三個注釋代碼做
    如下分析:寫出編譯后的偽代碼(僅供參考)
    編譯器更改后的函數原型void TheFunctionTwo(SimpleCat&)
    注釋1:
        SimpleCat myCat3;
        TheFunctionTwo(myCat3)
       {
          SimpleCat tempCat; 
          templCat.SimpleCat::SimpleCat();
          cout<<"in TheFunctionTwo tempCat指針 "<<&tempCat<<endl; 
          tempCat.SetAge(9999);
          myCat3.SimpleCat::SimpleCat(tempCat);
          tempCat.SimpleCat::~SimpleCat();
       }
    注釋2:
        SimpleCat myCat4;
        myCat4.SimpleCat::Simple();
        SimpleCat temp;
        TheFunctionTwo(temp)
       {
         SimpleCat tempCat; 
          templCat.SimpleCat::SimpleCat();
          cout<<"in TheFunctionTwo tempCat指針 "<<&tempCat<<endl; 
          tempCat.SetAge(9999);
          temp.SimpleCat::SimpleCat(tempCat);
          tempCat.SimpleCat::~SimpleCat();
       }
        myCat4.operator=(temp);
       temp.SimpleCat::~SimpleCat();
    注釋3: 
        //SimpleCat &rmyCat = TheFunctionTwo(); 
         SimpleCat temp;
         SimpleCat &rmyCat=temp;
        TheFunctionTwo(temp)
        {
          SimpleCat tempCat; 
          templCat.SimpleCat::SimpleCat();
          cout<<"in TheFunctionTwo tempCat指針 "<<&tempCat<<endl; 
          tempCat.SetAge(9999);
          temp.SimpleCat::SimpleCat(tempCat);
          tempCat.SimpleCat::~SimpleCat();
       }
    這樣就知道到底需要多少臨時對象了~~~~

    posted on 2009-05-11 15:22 Frank_Fang 閱讀(1372) 評論(4)  編輯  收藏 所屬分類: C++編程

    評論:
    # re: C++中函數值返回的過程中的問題,是否創建臨時變量 2009-05-11 15:24 | Frank_Fang
    有點搞不明白?有誰知道細節的發個評論,謝謝!!
      回復  更多評論
      
    # re: *C++中函數值返回的過程中的問題,是否創建臨時變量 2009-05-12 21:49 | Frank_Fang
    ---------------------------
    直接的調用默認拷貝構造函數的,這個語句一共創建了多少個對象
    SimpleCat constructor 0012FED8
    in TheFunctionTwo tempCat指針 0012FED8
    SimpleCat copy constructor0012FF30 從 0012FED8拷貝
    SimpleCat destructor0012FED8
    myCat3的地址是 0012FF30
    myCat3.GetAge() 9999
    SimpleCat destructor0012FF30



    ---------------------------
    調用默認的賦值運算符的,這個語句一共創建了多少個對象
    SimpleCat constructor 0012FF40
    SimpleCat constructor 0012FEC4
    in TheFunctionTwo tempCat指針 0012FEC4
    SimpleCat copy constructor0012FF04 從 0012FEC4拷貝
    SimpleCat destructor0012FEC4
    SimpleCat重載賦值運算符0012FF40 從 0012FF04賦值
    SimpleCat destructor0012FF04
    myCat4.GetAge() 9999
    SimpleCat destructor0012FF40


    ---------------------------
    TheFunctionTwo()返回的臨時對象賦給一個引用
    SimpleCat constructor 0012FED4
    in TheFunctionTwo tempCat指針 0012FED4
    SimpleCat copy constructor0012FF50 從 0012FED4拷貝
    SimpleCat destructor0012FED4
    打印一下返回的臨時對象的地址,臨時對象賦給引用之后就不會立即析構了---0012FF50
    rmCat.GetAge() 9999
    SimpleCat destructor0012FF50  回復  更多評論
      
    # re: *C++中函數值返回的過程中的問題,是否創建臨時變量 2009-05-12 21:50 | Frank_Fang
    非常感謝,終于弄明白了沒優化時的臨時對象問題了
    關于第三塊注釋中的
    將臨時對象賦給一個引用之后,這個臨時對象就不會立即析構了???
      回復  更多評論
      
    # re: *C++中函數值返回的過程中的問題,是否創建臨時變量 2009-06-06 22:37 | yyy
    151 //這種方式肯定是錯的,返回了局部變量的引用
    152 SimpleCat &TheFunctionThree()
    153 {
    154 SimpleCat tempCat;//局部變量
    155 cout<<"in TheFunctionThree tempCat指針 "<<&tempCat<<endl;
    156 tempCat.SetAge(9999);
    157 //返回時是否還創建一個臨時對象,已引用的形式
    158 return tempCat;
    159 }
    那為什么這種方式返回的臨時變量引用肯定是不正確的?  回復  更多評論
      
    主站蜘蛛池模板: 国内精品久久久久影院免费| 国产精品亚洲二区在线| 暖暖日本免费中文字幕| 国产专区一va亚洲v天堂| 特级aaaaaaaaa毛片免费视频| 黑人粗长大战亚洲女2021国产精品成人免费视频 | 亚洲视频免费播放| 最近免费最新高清中文字幕韩国 | 国产亚洲美女精品久久久| 午夜不卡AV免费| 亚洲色成人网站WWW永久| 中文字幕无码免费久久9一区9| 亚洲精品中文字幕无码蜜桃| 久草免费福利视频| 中文字幕亚洲第一在线| 久久精品免费全国观看国产| 亚洲色精品三区二区一区| 日本人的色道www免费一区| 免费在线观看一区| 亚洲AV无码一区东京热久久| 国产成人精品免费视频大全麻豆 | 暖暖在线视频免费视频| 亚洲综合色一区二区三区小说| 国产在线观看麻豆91精品免费| 亚洲熟妇无码一区二区三区导航| 波多野结衣免费视频观看| 久久精品免费网站网| 亚洲免费视频观看| 啊v在线免费观看| 久久久久国产免费| 伊人久久五月丁香综合中文亚洲| 一本久久综合亚洲鲁鲁五月天| 成人爽a毛片免费| 亚洲人精品亚洲人成在线| 亚洲综合精品网站| 四虎免费影院ww4164h| 午夜在线免费视频| 亚洲国产成人精品无码区在线秒播 | 一本一道dvd在线观看免费视频| 久久亚洲精品成人av无码网站| 女人18毛片a级毛片免费|