隨筆-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 中發(fā)生了一次值拷貝(賦值),也就是將item2+item3返回的局部變量拷貝給了item1之后,局部變量的作用域結(jié)束 
           
          可以返回局部變量,但是不能返回局部變量的引用。理解區(qū)分值和引用這兩個概念是學(xué)習(xí)C++的一大關(guān)鍵,明白這兩個概念之后,你就會理解為什么C++的類里面需要有拷貝構(gòu)造函數(shù),賦值操作符,析構(gòu)函數(shù)三個元素了以及其它的一些稀里古怪的用法和忠告了
          --

           

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

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


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

          ???
          目前的C++標準不允許在賦值的時候優(yōu)化掉函數(shù)返回的副本,也就是下面這兩種情況是不一樣的
           
          //這是賦值給item1,目前的標準下是會產(chǎn)生副本 temp
          Sales_item item1,item2,item3;
          item1=item2+item3;
           
          //這是拷貝構(gòu)造item1,編譯器通常會優(yōu)化(這個優(yōu)化區(qū)別下面所說的NRV優(yōu)化)掉副本,也就是不產(chǎn)生副本 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”: 只有靜態(tài)常量整型數(shù)據(jù)成員才可以在類中初始化

           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;//
          這個值區(qū)別于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好像沒有釋放內(nèi)存,怎么獲取的還是原來的值
           81     //可能在這個內(nèi)存區(qū)域存放的還是原來的?先new string后再調(diào)用也沒變,與編譯器有關(guān)還是什么??

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

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

           88     //這時問題來了,rCat.getAge()為123了
           89     SimpleCat *pSecond = new SimpleCat(123,444);
           90 
              
           91     cout<<"delete pCat后再使用rCat引用會發(fā)生什么問題???"<<
          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();//
          這個會發(fā)生內(nèi)存泄漏,在函數(shù)中申請的內(nèi)存會得不到釋放
           97                                      //myCat2是通過默認的拷貝函數(shù)來進行初始化的

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

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

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

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

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

          123     return 0;
          124 
          }
          125 

          126 
          127 //這個函數(shù)在返回時,是否會創(chuàng)建一個臨時引用變量???
          128 //
          TheFunctionTwo(SimpleCat &simpleCat)這個函數(shù)在傳遞參數(shù)時是否會創(chuàng)建一個臨時的引用變量
          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 //我要看對象被創(chuàng)建了幾次,是否創(chuàng)建臨時對象
          140 SimpleCat TheFunctionTwo()
          141 
          {
          142 
              SimpleCat tempCat;
          143     cout<<"in TheFunctionTwo tempCat指針 "<<&tempCat<<
          endl;
          144     tempCat.SetAge(9999
          );
          145     //返回時是否還創(chuàng)建一個臨時對象

          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     //返回時是否還創(chuàng)建一個臨時對象,已引用的形式

          158     return tempCat;
          159 
          }
          160 

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

          168 }
          169 

          170 
          171 

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

          正如4樓的所說~~~
          到底創(chuàng)建多少臨時對象,要視編譯器而定,看編譯器是否采用NVR...
          (其實一般情況下,NVR都是未采用的~),因此對后三個注釋代碼做
          如下分析:寫出編譯后的偽代碼(僅供參考)
          編譯器更改后的函數(shù)原型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 閱讀(1375) 評論(4)  編輯  收藏 所屬分類: C++編程

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



          ---------------------------
          調(diào)用默認的賦值運算符的,這個語句一共創(chuàng)建了多少個對象
          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
          打印一下返回的臨時對象的地址,臨時對象賦給引用之后就不會立即析構(gòu)了---0012FF50
          rmCat.GetAge() 9999
          SimpleCat destructor0012FF50  回復(fù)  更多評論
            
          # re: *C++中函數(shù)值返回的過程中的問題,是否創(chuàng)建臨時變量 2009-05-12 21:50 | Frank_Fang
          非常感謝,終于弄明白了沒優(yōu)化時的臨時對象問題了
          關(guān)于第三塊注釋中的
          將臨時對象賦給一個引用之后,這個臨時對象就不會立即析構(gòu)了???
            回復(fù)  更多評論
            
          # re: *C++中函數(shù)值返回的過程中的問題,是否創(chuàng)建臨時變量 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 //返回時是否還創(chuàng)建一個臨時對象,已引用的形式
          158 return tempCat;
          159 }
          那為什么這種方式返回的臨時變量引用肯定是不正確的?  回復(fù)  更多評論
            
          <2009年5月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(1)

          隨筆分類(204)

          隨筆檔案(100)

          收藏夾(8)

          牛人博客鏈接

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 梧州市| 新津县| 张家口市| 清涧县| 腾冲县| 泸西县| 阜宁县| 金堂县| 苍南县| 从江县| 介休市| 勃利县| 黄陵县| 长春市| 浮梁县| 东阿县| 广州市| 桓台县| 岳阳市| 静海县| 康平县| 平陆县| 涿鹿县| 香格里拉县| 沙湾县| 卓资县| 明星| 尼木县| 于都县| 江达县| 绥棱县| 金塔县| 宿松县| 哈密市| 开封市| 澄城县| 彩票| 伊金霍洛旗| 兴文县| 承德县| 陈巴尔虎旗|