<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #Item18: 當你要使用一個智能指針時,首先要想到的應該是`std::unique_ptr`.下面是一個很合理的假設:默認情況下,`std::unique_ptr`和原生指針同等大小,對于大多數操作(包括反引用),它們執行的底層指令也一樣。這就意味著,盡管在內存回收直來直往的情況下,`std::unique_ptr`也足以勝任原生指針輕巧快速的使用要求。 `std::unique_ptr`具現了獨占(exclusive ownership)語義,一個非空的`std::unique_ptr`永遠擁有它指向的對象,move一個`std::unique_ptr`會將所有權從源指針轉向目的指針(源指針指向為null)。拷貝一個`std::unique_ptr`是不允許的,假如說真的可以允許拷貝`std::unique_ptr`,那么將會有兩個`std::unique_ptr`指向同一塊資源區域,每一個都認為它自己擁有且可以摧毀那塊資源。因此,`std::unique_ptr`是一個move-only類型。當它面臨析構時,一個非空的`std::unique_ptr`會摧毀它所擁有的資源。默認情況下,`std::unique_ptr`會使用delete來釋放它所包裹的原生指針指向的空間。 `std::unique_ptr`的一個常見用法是作為一個工廠函數返回一個繼承層級中的一個特定類型的對象。假設我們有一個投資類型的繼承鏈。 [18-1.png] ```cpp class Investment { ... }; class Stock:public Investment { ... }; class Bond:public Investment { ... }; class RealEstate:public Investment { ... }; ``` 生產這種層級對象的工廠函數通常在堆上面分配一個對象并且返回一個指向它的指針。當不再需要使用時,調用者來決定是否刪除這個對象。這是一個絕佳的`std::unique_ptr`的使用場景。因為調用者獲得了由工廠函數分配的對象的所有權(并且是獨占性的),而且`std::unique_ptr`在自己即將被銷毀時,自動銷毀它所指向的空間。一個為Investment層級對象設計的工廠函數可以聲明如下: ```cpp template<typename... Ts> std::unique_ptr<Investment> makeInvestment(Ts&&... params);// return std::unique_ptr // to an object created // from the given args ``` 調用者可以在一處代碼塊中使用返回的`std::unique_ptr`: ```cpp { ... auto pInvestment = makeInvestment( arguments ); //pInvestment is of type std::unique_ptr<Investment> ... }//destroy *pInvestment ``` 他們也可以使用在擁有權轉移的場景中,例如當工廠函數返回的`std::unique_ptr`可以移動到一個容器中,這個容器隨即被移動到一個對象的數據成員上,該對象隨后即被銷毀。當該對象被銷毀后,該對象的`std::unique_ptr`數據成員也隨即被銷毀,它的析構會引發工廠返回的資源被銷毀。如果擁有鏈因為異常或者其他的異常控制流(如,函數過早返回或者for循環中的break語句)中斷,最終擁有資源的`std::unique_ptr`仍會調用它的析構函數(注解:這條規則仍有例外:大多數源自于程序的非正常中斷。一個從一個線程主函數(如程序的初始線程的main函數)傳遞出來的異常,或者一個違背了noexpect規范(請看Item 14)的異常,本地對象不會得到析構,如果`std::abort`或者其他的exit函數(如`std::_Exit`, `std::exit`,或者`std::quick_exit`)被調用,那么它們肯定不會被析構),`std::unique_ptr`管理的資源也因此得到釋放。 默認情況下,析構函數會使用delete。但是,我們也可以在它的構造過程中指定特定的析構方法(custom deleters):當資源被回收時,傳入的特定的析構方法(函數對象,或者是特定的lambda表達式)會被調用。對于我們的例子來說,如果被makeInvestment創建的對象不應該直接被deleted,而是首先要有一條log記錄下來,我們就可以這樣實現makeInvestment(當你看到意圖不是很明顯的代碼時,請注意看注釋) ```cpp auto delInvmt = [](Investment* pInvestment){ makeLogEntry(pInvestment); delete pInvestment; };//custom deleter(a lambda expression) template<typename... Ts> std::unique_ptr<Investment, decltype(delInvmt)>//revised return type makeInvestment(Ts&&... params) { std::unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt);//ptr to be returned if ( /* a Stock object should be created */ ) { pInv.reset(new Stock(std::forward<Ts>(params)...)); } else if ( /* a Bond object should be created */ ) { pInv.reset(new Bond(std::forward<Ts>(params)...)); } else if ( /* a RealEstate object should be created */ ) { pInv.reset(new RealEstate(std::forward<Ts>(params)...)); } return pInv; } ``` 我之前說過,當使用默認的析構方法時(即,delete),你可以假設`std::unique_ptr`對象的大小和原生指針一樣。當`std::unique_ptr`用到了自定義的deleter時,情況可就不一樣了。函數指針類型的deleter會使得`std::unique_ptr`的大小增長到一個字節到兩個字節。對于deleters是函數對象的`std::unique_ptr`,大小的改變依賴于函數對象內部要存儲多少狀態。無狀態的函數對象(如,沒有captures的lambda expressions) 不會導致額外的大小開銷。這就意味著當一個自定義的deleter既可以實現為一個函數對象或者一個無捕獲狀態的lambda表達式時,lambda是第一優先選擇: ```cpp auto delInvmt1 = [](Investment* pInvestment) { makeLogEntry(pInvestment); delete pInvestment; } //custom deleter as stateless lambda template<typename... Ts> std::unique_ptr<Investment, decltype(delInvmt1)> makeInvestment(Ts&&.. args);//return type has size of Investment* void delInvmt2(Investment* pInvestment) { makeLogEntry(pInvestment); delete pInvestment; } template<typename... Ts> std::unique_ptr<Investment,(void *)(Investment*)> makeInvestment(Ts&&... params);//return type has size of Investment* plus at least size of function pointer! ``` 帶有過多狀態的函數對象的deleters是使得`std::unique_ptr`的大小得到顯著的增加。如果你發現一個自定義的deleter使得你的`std::unique_ptr`大到無法接受,請考慮重新改變你的設計。 `std::unique_ptr`會產生兩種格式,一種是獨立的對象(std::unique_ptr<T>),另外一種是數組(`std::unique_ptr<T[]>`).因此,std::unique_ptr指向的內容從來不會產生任何歧義性。它的API是專門為了你使用的格式來設計的.例如,單對象格式中沒有過索引操作符(操作符[]),數組格式則沒有解引用操作符(操作符*和操作符->) `std::unique_ptr`的數組格式對你來說可能是華而不實的東東,因為和原生的array相比,`std::array`,`std::vector`以及`std::string`幾乎是更好的數據結構選擇。我所想到的唯一的std::unique_ptr<T[]>有意義的使用場景是,你使用了C-like API來返回一個指向堆內分配的數組的原生指針,而且你像對之接管擁有權。 C++11使用`std::unique_ptr`來表述獨占所有權。但是它的一項最引人注目的特性就是它可以輕易且有效的轉化為`std::shared_ptr`: ```cpp std::shared_ptr<Investment> sp = makeInvestment(arguments);//converts std::unique_ptr to std::shared_ptr ``` 這就是`std::unique_ptr`很適合作為工廠函數返回值類型的原因。工廠函數不知道調用者想使用獨占性的擁有語義還是共享式的擁有語義(即`std::share_ptr`).通過返回`std::unique_ptr`,工廠函數將選擇權移交給了調用者,調用者在需要的時候可以將`std::unique_ptr`轉化為它最富有靈活性的兄弟(如果想了解更多關于`std::shared_ptr`,請移步Item 19) |要記住的東西| |:--------- | |`std::unique_ptr`是一個具有開銷小,速度快,`move-only`特定的智能指針,使用獨占擁有方式來管理資源。| |默認情況下,釋放資源由delete來完成,也可以指定自定義的析構函數來替代。但是具有豐富狀態的deleters和以函數指針作為deleters增大了`std::unique_ptr`的存儲開銷| |很容易將一個`std::unique_ptr`轉化為`std::shared_ptr`|
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看