• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

            這幾天開(kāi)始拜讀侯捷先生和孟巖先生的譯作《C++標(biāo)準(zhǔn)程序庫(kù):自修教程與參考手冊(cè)》 。兩位先生確實(shí)譯功上乘,讀得很順。但是讀到P55頁(yè)關(guān)于auto_ptr_ref的討論,卻百思不得其解:為什么需要引入auto_ptr_ref這個(gè)輔助類(lèi)呢?

             

            從書(shū)中描述來(lái)看,仿佛與拷貝構(gòu)造函數(shù) 、右值 、類(lèi)型轉(zhuǎn)換 有關(guān)。于是,結(jié)合auto_ptr的源代碼,google之、baidu之,找了一推資料,終于初步 搞清該問(wèn)題。

             

            auto_ptr的擁有權(quán)

            C++常見(jiàn)的智能指針有std::auto_ptr、boost::shared_ptr、boost::scoped_ptr、boost::shared_array、boost::scoped_array等。auto_ptr只是其中一種而已。但是,為什么auto_ptr才有auto_ptr_ref ,而boost::shared_ptr卻沒(méi)有shared_ptr_ref呢?

             

            答案與auto_ptr的特性有關(guān)。auto_ptr強(qiáng)調(diào)對(duì)資源的擁有權(quán) (ownership)。也就是說(shuō),auto_ptr是"它所指對(duì)象"的擁有者。而一個(gè)對(duì)象只能屬于一個(gè)擁有者,嚴(yán)禁一物二主,否則就是重婚罪,意料外的災(zāi)難將隨之而來(lái)。

             

            為了保證auto_ptr的擁有權(quán)唯一,auto_ptr的拷貝構(gòu)造函數(shù)和賦值操作符做了這樣一件事情:移除另一個(gè)auto_ptr的擁有權(quán) 。為了說(shuō)明擁有權(quán)的轉(zhuǎn)移 ,請(qǐng)看下面的代碼示例:

            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4.   
            5. int main(int argc, char **argv){  
            6.     auto_ptr<int> ptr1(new int(1));  
            7.     auto_ptr<int> ptr2(ptr1); //ptr1的擁有權(quán)被轉(zhuǎn)移到ptr2  
            8.   
            9.     auto_ptr<int> ptr3(NULL);  
            10.     ptr3 = ptr2;                //ptr2的擁有權(quán)被轉(zhuǎn)移到ptr3  
            11.   
            12.     cout<<ptr1.get()<<endl;     //結(jié)果為0  
            13.     cout<<ptr2.get()<<endl;     //結(jié)果為0  
            14.     cout<<*ptr3<<endl;          //結(jié)果為1  


            auto_ptr的拷貝構(gòu)造函數(shù)與賦值操作符  

            由于需要實(shí)現(xiàn)擁有權(quán)的轉(zhuǎn)移,auto_ptr的拷貝構(gòu)造函數(shù)和賦值操作符,與一般類(lèi)的做法不太相同。我們可以看看MinGW 5.1.6實(shí)現(xiàn)的auto_ptr源代碼:

            Cpp代碼  收藏代碼
            1.  /** 
            2.  *  @brief  An %auto_ptr can be constructed from another %auto_ptr. 
            3.  *  @param  a  Another %auto_ptr of the same type. 
            4.  * 
            5.  *  This object now @e owns the object previously owned by @a a, 
            6.  *  which has given up ownsership. 
            7.  */  
            8. auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) {}  
            9.   
            10. /** 
            11.  *  @brief  %auto_ptr assignment operator. 
            12.  *  @param  a  Another %auto_ptr of the same type. 
            13.  * 
            14.  *  This object now @e owns the object previously owned by @a a, 
            15.  *  which has given up ownsership.  The object that this one @e 
            16.  *  used to own and track has been deleted. 
            17.  */  
            18. auto_ptr&  
            19. operator=(auto_ptr& __a) throw () {  
            20.     reset(__a.release());  
            21.     return *this;  
            22. }  

             

                可以看到,auto_ptr的拷貝構(gòu)造函數(shù)、賦值操作符,它們的參數(shù)都是auto_ptr& ,而不是auto_ptr const & 。

             

                一般來(lái)說(shuō),類(lèi)的拷貝構(gòu)造函數(shù)和賦值操作符的參數(shù)都是const &。但是auto_ptr的做法也是合理的:確保擁有權(quán)能夠轉(zhuǎn)移 。

             

                如果auto_ptr的拷貝構(gòu)造函數(shù)和賦值操作符的參數(shù)是auto_ptr const & ,那么實(shí)參的擁有權(quán)將不能轉(zhuǎn)移。因?yàn)檗D(zhuǎn)移擁有權(quán)需要修改auto_ptr的成員變量,而實(shí)參確是一個(gè)const對(duì)象,不允許修改。

             

            右值與const &

            假設(shè)我們想寫(xiě)出下面的代碼:

            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4.   
            5. int main(int argc, char **argv) {  
            6.     auto_ptr<int> ptr1(auto_ptr<int>(new int(1)));  //使用臨時(shí)對(duì)象進(jìn)行拷貝構(gòu)造  
            7.     auto_ptr<int> ptr2(NULL);  
            8.     ptr2 = (auto_ptr<int>(new int(2)));           //使用臨時(shí)對(duì)象進(jìn)行賦值  
            9. }  

             

                假設(shè)沒(méi)有定義auto_ptr_ref類(lèi)及相關(guān)的函數(shù),那么這段代碼將不能通過(guò)編譯。主要的原因是,拷貝構(gòu)造函數(shù)及賦值操作符的參數(shù):auto_ptr<int>(new int(1))和 auto_ptr<int>(new int(2)) 都是臨時(shí)對(duì)象 。臨時(shí)對(duì)象屬于典型的右值 ,而非const &是不能指向右值的 (參見(jiàn)More Effective C++ ,Item 19)。auto_ptr的拷貝構(gòu)造函數(shù)及賦值操作符的參數(shù)類(lèi)型恰恰是auto_ptr&,明顯 非const &。

             

                同理,下面的兩段代碼,也不會(huì)通過(guò)編譯:

            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4. auto_ptr<int> f();  
            5. int main(int argc, char **argv) {  
            6.     auto_ptr<int> ptr3(f());  //使用臨時(shí)對(duì)象進(jìn)行拷貝構(gòu)造  
            7.     auto_ptr<int> ptr4(NULL);  
            8.     ptr4 = f();               //使用臨時(shí)對(duì)象進(jìn)行賦值  
            9. }  
            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4. auto_ptr<int> f(){  
            5.     return auto_ptr<int>(new int(3));  //這里其實(shí)也使用臨時(shí)對(duì)象進(jìn)行拷貝構(gòu)造  
            6. }  
             

                普通類(lèi)不會(huì)遇到這個(gè)問(wèn)題,是因?yàn)樗麄兊目截悩?gòu)造函數(shù)及賦值操作符(不管是用戶(hù)定義還是編譯器生成的版本),參數(shù)都是const &。

             

            auto_ptr_ref之目的

            傳說(shuō)當(dāng)年C++標(biāo)準(zhǔn)委員會(huì)的好多國(guó)家,因?yàn)檫@個(gè)問(wèn)題都想把a(bǔ)uto_ptr從標(biāo)準(zhǔn)庫(kù)中剔除。好在Bill Gibbons和Greg Colvin創(chuàng)造性地提出了auto_ptr_ref,解決了這一問(wèn)題,世界清靜了。

             

            auto_ptr_ref之原理

                很顯然,下面的構(gòu)造函數(shù),是可以接收auto_ptr臨時(shí)對(duì)象的。

            Cpp代碼  收藏代碼
            1. auto_ptr(auto_ptr __a) throw() : _M_ptr(__a.release()) { }  

             

                但另一個(gè)問(wèn)題也很顯然:上述構(gòu)造函數(shù)不能通過(guò)編譯。如果能通過(guò)編譯,就會(huì)陷入循環(huán)調(diào)用。我們稍作修改:

            Cpp代碼  收藏代碼
            1. auto_ptr(auto_ptr_ref<element_type> __ref) throw()  //element_type就是auto_ptr的模板參數(shù)。  
            2.       : _M_ptr(__ref._M_ptr) { }   

             

                該版本的構(gòu)造函數(shù),可以接收auto_ptr_ref的臨時(shí)對(duì)象。如果auto_ptr可以隱式轉(zhuǎn)換到auto_ptr_ref,那么我們就能夠用auto_ptr臨時(shí)對(duì)象來(lái)調(diào)用該構(gòu)造函數(shù)。這個(gè)隱式轉(zhuǎn)換不難實(shí)現(xiàn):

            Cpp代碼  收藏代碼
            1. template<typename _Tp1>  
            2.         operator auto_ptr_ref<_Tp1>() throw()  
            3.         { return auto_ptr_ref<_Tp1>(this->release()); }  
             

                至此,我們可以寫(xiě)出下面的代碼,并可以通過(guò)編譯:

            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4.   
            5. int main(int argc, char **argv) {  
            6.     auto_ptr<int> ptr1(auto_ptr<int>(new int(1)));  //調(diào)用auto_ptr_ref版本的構(gòu)造函數(shù)  
            7. }  

             

               同理,如果我們?cè)偬峁┫旅娴暮瘮?shù):

            Cpp代碼  收藏代碼
            1. auto_ptr&  
            2.      operator=(auto_ptr_ref<element_type> __ref) throw()  
            3.      {  
            4. if (__ref._M_ptr != this->get())  
            5.   {  
            6.     delete _M_ptr;  
            7.     _M_ptr = __ref._M_ptr;  
            8.   }  
            9. return *this;  
            10.      }  

             

                那么,下面的代碼也可以通過(guò)編譯:

            Cpp代碼  收藏代碼
            1. #include <iostream>  
            2. #include <memory>  
            3. using namespace std;  
            4.   
            5. int main(int argc, char **argv) {  
            6.     auto_ptr<int> ptr2(NULL);  
            7.     ptr2 = (auto_ptr<int>(new int(2)));  //調(diào)用auto_ptr_ref版本的賦值操作符  
            8. }  

             

            auto_ptr_ref之本質(zhì)

            本質(zhì)上,auto_ptr_ref賦予了auto_ptr“引用”的語(yǔ)義,這一點(diǎn)可以從auto_ptr_ref的注釋看出:

            Cpp代碼  收藏代碼
            1. /** 
            2.    *  A wrapper class to provide auto_ptr with reference semantics. 
            3.    *  For example, an auto_ptr can be assigned (or constructed from) 
            4.    *  the result of a function which returns an auto_ptr by value. 
            5.    * 
            6.    *  All the auto_ptr_ref stuff should happen behind the scenes. 
            7.    */  
            8.   template<typename _Tp1>  
            9.     struct auto_ptr_ref  
            10.     {  
            11.       _Tp1* _M_ptr;  
            12.         
            13.       explicit  
            14.       auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }  
            15.     };  


            auto_ptr_ref之代碼

            這里列出auto_ptr_ref相關(guān)的函數(shù),共參考:

            Cpp代碼  收藏代碼
            1. auto_ptr(auto_ptr_ref<element_type> __ref) throw()  
            2. : _M_ptr(__ref._M_ptr) {}  
            3.   
            4. auto_ptr&  
            5. operator=(auto_ptr_ref<element_type> __ref) throw () {  
            6.     if (__ref._M_ptr != this->get()) {  
            7.         delete _M_ptr;  
            8.         _M_ptr = __ref._M_ptr;  
            9.     }  
            10.     return *this;  
            11. }  
            12.   
            13. template<typename _Tp1>  
            14. operator auto_ptr_ref<_Tp1>() throw () {  
            15.     return auto_ptr_ref<_Tp1> (this->release());  
            16. }  
            17.   
            18. template<typename _Tp1>  
            19. operator auto_ptr<_Tp1>() throw () {  
            20.     return auto_ptr<_Tp1> (this->release());  
            21. }  

             參考資料

            auto_ptr之變遷

            auto_ptr實(shí)現(xiàn)之我見(jiàn)

            auto_ptr_ref的奇妙(上)

            auto_ptr_ref的奇妙(下)

            auto_ptr_ref 的目的是什么

            關(guān)于auto_ptr_ref的一點(diǎn)問(wèn)題

            左值和右值

            轉(zhuǎn)
            自:http://www.iteye.com/topic/746062

            一本久道久久综合狠狠躁AV| 97久久天天综合色天天综合色hd| 国产69精品久久久久9999| 精品国产青草久久久久福利| 久久人人爽人人爽人人片AV麻豆| 久久久精品久久久久久| 国产精品久久久久免费a∨| 精品国产乱码久久久久久呢| 久久久国产精品亚洲一区| 伊人久久综合热线大杳蕉下载| 久久精品无码一区二区app| 久久精品桃花综合| 久久99热狠狠色精品一区| 久久精品国产一区二区三区不卡| 99蜜桃臀久久久欧美精品网站| 久久99精品久久久久久动态图| 国产农村妇女毛片精品久久| 久久久久久精品免费看SSS| 久久久青草青青亚洲国产免观| 亚洲欧美久久久久9999 | 97久久精品无码一区二区| 久久99亚洲综合精品首页| 无码人妻少妇久久中文字幕蜜桃 | 亚洲精品乱码久久久久久不卡| 一本久久a久久精品亚洲| 久久久久国产日韩精品网站| 99精品久久久久中文字幕| 久久综合久久综合亚洲| 国产精品亚洲美女久久久| 久久久久久九九99精品| 国产精品久久久久久五月尺| 精品久久久久久无码国产| 国产精品久久99| 亚洲AV无码1区2区久久| 午夜精品久久久内射近拍高清| 国产精品久久久久久一区二区三区| 久久综合亚洲色一区二区三区| 久久久久国产一区二区三区| 一本伊大人香蕉久久网手机| 国产成人久久AV免费| 欧美一区二区三区久久综|