<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                簡介 ==== 如果你是一個像我一樣有經驗的C++程序猿,當初次體驗C++11時,“啊,就是他,我明白了,這就是C++”。但是自從你學習了更多的內容,你會驚訝于他的變化。`auto`類型聲明,基于區間的`for`循環,lambda表達式和右值引用改變了C++的樣貌,還有新的并發API。除此之外,還包括一些合服語言習慣的改動。0和`typedef`都已經過時,`nullptr`和別名聲明(alias declarations)強勢登場。`enum`需要被作用域限制。現在更加建議使用在內部實現的智能指針。移動對象要比拷貝一個對象代價更小。 關于C++11我們要學習很多,還沒有提C++14呢。 更重要的是,要想有效的利用好這些特性需要學習很多的東西。如果你擁有了關于“現代”C++特性,知識儲備的基礎,但是希望得到一個關于如何正確駕馭這些特性來創造運行正確,高效,可維護和可移植的軟件的向導,搜尋的過程是非常具有挑戰性的。這就是這本書的目的。他不是來介紹C++11和C++14的新特新的,而是來介紹如何使用他們的高效做法。 這本書的內容被封裝成一系列叫做“條款”(item)的東東。想了解更多的關于類型推導的形式嗎?或者想知道什么時候用(或者不用)`auto`聲明嗎?你對為什么`const`成員函數必須保證線程安全感興趣嗎?想知道怎么利用`std::unique_ptr`實現Pimpl Idiom,為什么不建議你在lambda表達式里面使用默認的捕捉模式,或者`std::atomic` 和`volatile`有什么區別?答案都在這本書里面。更多的是平臺獨立,標準兼容的答案。這本書講的是可移植的C++。 書中的條款是指導性建議,并不是法則,因為這些是有意外情況的。重要的不是每條條款帶來的建議,而是這些建議背后的道理。一旦你理解了他們,你就可以在你的項目中扮演一個決策者的地位來判斷他們是不是違背某個條款的指導性。這本書的目的不是告訴你什么要做,什么不要做,而是要你對C++11和C++14的基礎之上進行深層理解。 術語和約定 ---------- 為了讓我們之間互相理解,在一開始我們預定C++的一些術語是很重要的。到目前為止有四份關于C++的官方版本,每一份依據對應ISO標準草案定制的年份來命名:C++98,C++03,C++11和C++14。C++98和C++03只是在技術細節上略有區別,在這本書里面我把它們都稱之為C++98。當我提到C++11的時候,指的是C++11和C++14,因為C++14就是一個C++11的超集。當我寫到C++14的時候,是特指C++14。當我簡單的提到C++的時候,應該指的是所有的語言版本。 |我的表述|我所指的語言版本| | :----: | :------------: | |C++|所有的版本| |C++98|C++98和C++03| |C++11|C++11和C++14| |C++14|C++14| 一般來說,我可能絕大時候說C++對運行效率比較重視(對所有的版本都是對的),但是C++98缺乏對并發的支持(這個對于C++03和C++98是對的),但是C++11支持lambda表達式(對C++11和C++14是對的),C++14提供了通用的函數返回值類型推導(對C++14是對的)。 C++11的最普遍的特性是移動語義(move semantics),移動語義的基石是從那些左值中區分出右值。這是因為右值標志著對象是可以在移動操作中使用的而左值通常不是。在概念上來說(在實際中不一定),右值代表著你可以引用的臨時對象,不管是通過變量名還是通過一個指針或者左值引用。 一個有用的,有啟發意義的判斷一個表達式是左值的方法是取它的地址。如果可以取地址,它基本上就是一個左值。如果不行,通常來說是一個右值。這個啟發式的特性可以很好的幫助我們記住一個表達式的類型,不管他是一個左值還是一個右值。也就是說,給定一個類型`T`,你可以得到類型`T`的左值同時也可以得到它的右值。當處理一個有右值引用的參數時需要銘記于心,因為參數本身是個左值: ```cpp class Widget { public: Widget(Widget&& rhs); // rhs是一個左值,盡管他 … // 有一個右值引用類型 }; ``` 這里,在`Widget`的移動構造函數里面完全可以取得`rds`的地址,所以`rds`是一個左值盡管他的類型是個右值引用。(因為類似的原因,所有的參數都是左值。) 這段代碼片段闡述了我一般要遵守的幾條原則: * 類名是`Widget`。我通常會使用`Widget`來代指一個任意的用戶自定義類型。我使用`Widget`是不會聲明他的,除非我要展示類的特殊細節。 * 我使用的參數名字叫做`rhs`(“right-hand side”)。他是我在移動操作(移動構造函數和移動賦值運算符)中和拷貝操作(拷貝構造函數和復制賦值運算符)喜歡使用的名字。我還把他用在二元運算符的右邊的參數: ```cpp Matrix operator+(const Matrix& lhs, const Matrix& rhs); ``` 不要驚訝,我希望`lhs`代表“left-hand side”。 * 我在代碼和注釋中使用這種格式向你表示你要注意這些東西。在`Widget`的移動構造函數中,我高亮了`rhs`和部分注釋來表明`rhs`是一個左值。(很抱歉,譯者使用的Markdown語法暫時無法控制代碼里面的高亮——譯者注。)高亮代碼從根本上說不好也不壞。他只是一段你需要加以注意的特殊的代碼。 * 我使用“…”來表示“在此處有其他的代碼”。這種比較窄的省略號和用在C++11源代碼里面的的變長模板的寬省略號(“...”)是不一樣的。這聽起來比較困惑。舉個例子: ```cpp template<typename... Ts> // 這里是C++ void processVals(const Ts&... params) // 源代碼里面的 { // 省略號 … // 此處意味著 } // “有些代碼著這里省略了” ``` `processVals`展示了我在模板中使用`typename`關鍵字,但是這只是一個個人習慣;關鍵字`class`也可以工作的正常(這里是不嚴謹的,nested dependent type name使用的時候,`typename`是不能替換成`class`的——譯者注)。當我要使用C++標準展示代碼,我會使用`class`來做參數類型類型聲明,因為標準就是這樣做的。 當一個對象使用另外一個類型相同的對象來初始化的時候,新的對象稱作一份初始化對象的拷貝,甚至這個拷貝是基于移動構造函數實現的也叫做對象的拷貝。遺憾的是,在C++中沒有一個術語是用來區分拷貝構造個移動構造的拷貝。 ```cpp void someFunc(Widget w); // someFunc的參數w是以值傳送 Widget wid; // wid是個Widget的對象 someFunc(wid); // 在這個someFunc調用里面,w是通過 // 拷貝構造函數生成wid的一個拷貝 someFunc(std::move(wid)); // 在這個someFunc調用里面,w是通過 // 移動構造函數生成wid的一個拷貝 ``` 在一個函數調用里面,在函數的調用方的表達式是函數的實參。這些表達式被用來初始化函數的形參。在上面的代碼中的第一次調用`someFunc`,實參是`wid`。在第二次調用的地方,實參是 `std::move(wid)`。兩次調用的形參都是`w`。實參和形參的區別是很重要的,因為形參只能是左值,但是給他們初始化的實參即有可能是右值也有可能是左值。這和完美轉發的過程是密切相關的,在完美轉發中一個傳遞給一個函數的實參再傳遞給第二個函數,以此來保證原始的參數的右值特性或者左值特性被保留。(完美轉發的細節在條款30中)。 良好設計的函數是異常安全的,也就意味著他們至少接受基本的異常保證(弱保證)。這樣的函數確保調用者觸發異常,程序任然保持正常(沒有數據結構被損壞)沒有資源泄露。函數保證強壯的異常安全(強保證)會確保程序發生異常的時候,程序的運行狀態和之前調用這個函數的狀態是一樣的。 當我提到函數對象(仿函數也屬于其中一種——譯者注)的時候,我通常意味著這個類型支持`operator()`操作。也就是說,這個對象的行為像一個函數。有時候我會在一些更加通用的地方來使用這種說法(“`functionName(arguments)`”)。更加廣義的定義不僅僅包含那些支持`operator()`的對象,也包括函數和C風格的函數指針。(狹義的定義來自于C++98,廣義的定義來自于C++11)。添加成員函數指針被稱之為可調用對象(callable objects)。通常你可以忽略他們的區別,僅僅認識到在C++中函數對象和可調用對象可以被用在一些函數調用的語法結構里面。 通過lambda表達式創造的函數對象通常稱之為閉包(closure)。通常很少區分lambda表達式和它產生的閉包,我通常用lambdas來代指它們。類似的,我很少區分函數模板(生成函數的模板)和模板函數(利用函數模板生成的函數)。對于類模板和模板類也是如此。 在C++許多東西可以聲明和定義。聲明把類型和名字帶入我們的視野但是細節啥都不給,例如是在哪兒放置的存儲空間,問題是怎么實現的之類的: ```cpp extern int x; // 對象聲明 class Widgets; // class聲明 bool func(const Widget& w); // 函數聲明 enum class Color; // 被作用域包裹的enum聲明(參考條款10) ``` 定義提供存儲地址或者實現的細節: ```cpp int x; // 對象定義 class Widget { … // class定義 }; bool func(const Widget& w) { return w.size() < 10; } // 函數定義 enum class Color { Yellow, Red, Blue }; // 被作用域包裹的enum定義 ``` 一個定義當然是需要對應一個聲明,除非定義對某個東西非常重要,我通常指的是聲明。 我指一個函數的簽名是由函數的參數和返回值確定的。函數和參數的名字并不是函數簽名的一部分。在上述代碼中,`func`的簽名是`bool(const Widget&)`。函數聲明的組成部分除了他的參數和返回值(比如如果有`noexcept`或者`constexpr`)都被排除在外。(`noexcept`和`constexpr`在條款14和條款15中被討論)。正式的“簽名”的定義和我的略有出入。但對于這本書來說,我的定義會非常有用。(正式的定義會排除返回值類型)。 新的C++標準通常兼容于老的代碼,但是有的時候標準化委員會會廢棄一些特性。這些特性很有可能在未來的標準化進程中被移除。編譯器可能對這些即將廢棄的特性沒有任何警告,但是你最好要避免使用它們。不僅僅是因為他們會給將來的代碼帶來頭痛,而且他們通常是有好的實現來代替它們。舉個例子,`std::auto_ptr`被C++11所廢棄,因為有更好的相同功能的`std::unique_ptr`,而且能做的更好。(`std::auto_ptr`本來是設計用來防止內存泄露的智能指針,但是為了使用它你必須要注意一堆坑,一般舊的C++書籍也會說明不建議使用——譯者注)。 有些時候標準說某個操作會導致未定義行為,這意味著運行時的行為無法預測,不用說,你是需要避開這種不確定性的。一個未確定性的例子是使用方括號(“[]”)去索引超出`std::vector`的長度,從一個未初始化的迭代器取值,或者是有趣的數據競爭(兩個或者更多的線程,至少有一個是生產者,同時訪問同一塊內存區域)。 我把直接從new返回的原始指針叫做內建指針。一個原始指針的反義詞就是智能指針。智能指針通常重載了指針取值運算符(`operator->`和`operator*`),在條款20里面會解釋`std::weak_ptr`是個特殊情況。 在源碼注釋里面,我通常把“構造函數”簡稱為ctor,“析構函數”簡稱為dtor。 報告Bug和建議優化 ----------------- 我盡我的努力去讓這本書能夠帶來清楚,準確,有用的信息,但是總是可以再度改善完美的。如果你發現書中的任何錯誤(技術的,解釋的,語法的,印刷的,等等)或者你有一些關于讓這本書更好的建議,可以給我發郵件 emc++@aristeia.com。關于修訂Effective Modern C++可以交付于書新版,但是我不能確定出我不知道的問題。 查看這本書已經發現的問題,審核本書的勘誤。[http://www.aristeia.com/BookErrata/emc++-errata.html](http://www.aristeia.com/BookErrata/emc++-errata.html)。
                  <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>

                              哎呀哎呀视频在线观看