日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

几个方便编程的C++特性

發(fā)布時(shí)間:2023/12/31 c/c++ 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 几个方便编程的C++特性 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言:

??????? C++11的自動(dòng)化特性給編程提供了不少方便,同時(shí)也給調(diào)試增加了很多負(fù)擔(dān),至于取舍看程序員的風(fēng)格和側(cè)重而定。


auto:自動(dòng)類型推斷

  在C++11之前,auto關(guān)鍵字用來(lái)指定存儲(chǔ)期。在新標(biāo)準(zhǔn)中,它的功能變?yōu)轭愋屯?/span>斷。auto現(xiàn)在成了一個(gè)類型的占位符,通知編譯器去根據(jù)初始化 代碼推斷所聲明變量的真實(shí)類型。各種作用域內(nèi)聲明變量都可以用到它。例如,名空間中,程序塊中,或是for循環(huán)的初始化語(yǔ)句中。

  auto i = 42; // i is an int auto l = 42LL; // l is an long long auto p = new foo(); // p is a foo*

  使用auto通常意味著更短的代碼(除非你所用類型是int,它會(huì)比auto少一個(gè)字母)。試想一下當(dāng)你遍歷STL容器時(shí)需要聲明的那些迭代器(iterator)。現(xiàn)在不需要去聲明那些typedef就可以得到簡(jiǎn)潔的代碼了。

  std::map> map; for(auto it = begin(map); it != end(map); ++it) { }

  需要注意的是,auto不能用來(lái)聲明函數(shù)的返回值。但如果函數(shù)有一個(gè)尾隨的返回類型時(shí),auto是可以出現(xiàn)在函數(shù)聲明中返回值位置。這種情況下,auto 并不是告訴編譯器去推斷返回類型,而是指引編譯器去函數(shù)的末端尋找返回值類型。在下面這個(gè)例子中,函數(shù)的返回值類型就是operator+操作符作用在 T1、T2類型變量上的返回值類型。

  template auto compose(T1 t1, T2 t2) -> decltype(t1 + t2) { return t1+t2; } auto v = compose(2, 3.14); // v's type is double

?????? 注:最主要的是 在小范圍迭代時(shí) 不用刻意去注意其類型,節(jié)省了編程時(shí)間....


nullptr 空指針?

  以前都是用0來(lái)表示空指針的,但由于0可以被隱式類型轉(zhuǎn)換為整形,這就會(huì)存在一些問(wèn)題。關(guān)鍵字nullptr是std::nullptr_t類型的 值,用來(lái)指代空指針。nullptr和任何指針類型以及類成員指針類型的空值之間可以發(fā)生隱式類型轉(zhuǎn)換,同樣也可以隱式轉(zhuǎn)換為bool型(取值為 false)。但是不存在到整形的隱式類型轉(zhuǎn)換。

  void foo(int* p) {} void bar(std::shared_ptr p) {} int* p1 = NULL; int* p2 = nullptr; if(p1 == p2) { } foo(nullptr); bar(nullptr); bool f = nullptr; int i = nullptr; // error: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type

  為了向前兼容,0仍然是個(gè)合法的空指針值。


基于范圍的for循環(huán):

???????? C++使用了800行STL代碼就是為了讓一個(gè)遍歷語(yǔ)句更像python這種動(dòng)態(tài)語(yǔ)言.

  為了在遍歷容器時(shí)支持”foreach”用法,C++11擴(kuò)展了for語(yǔ)句的語(yǔ)法。用這個(gè)新的寫法,可以遍歷C類型的數(shù)組、初始化列表以及任何重載了非成員的begin()和end()函數(shù)的類型。(這是向動(dòng)態(tài)語(yǔ)言看齊啊...)

  如果你只是想對(duì)集合或數(shù)組的每個(gè)元素做一些操作,而不關(guān)心下標(biāo)、迭代器位置或者元素個(gè)數(shù),那么這種foreach的for循環(huán)將會(huì)非常有用。

std::map> map; std::vector v; v.push_back(1);v.push_back(2); v.push_back(3); map["one"] = v;for(const auto& kvp : map) {std::cout << kvp.first << std::endl;for(auto v : kvp.second) {std::cout << v << std::endl;} }int arr[] = {1,2,3,4,5}; for(int& e : arr) {e = e*e; } //C++ 11 CPP 11 features

Smart Pointers 智能指針,有計(jì)數(shù)的指針.

  已經(jīng)有成千上萬(wàn)的文章討論這個(gè)問(wèn)題了,所以我只想說(shuō):現(xiàn)在能使用的,帶引用計(jì)數(shù),并且能自動(dòng)釋放內(nèi)存的智能指針包括以下幾種:

  unique_ptr: 如果內(nèi)存資源的所有權(quán)不需要共享,就應(yīng)當(dāng)使用這個(gè)(它沒(méi)有拷貝構(gòu)造函數(shù)),但是它可以轉(zhuǎn)讓給另一個(gè)unique_ptr(存在move構(gòu)造函數(shù))。

  shared_ptr: 如果內(nèi)存資源需要共享,那么使用這個(gè)(所以叫這個(gè)名字)。

  weak_ptr: 持有被shared_ptr所管理對(duì)象的引用,但是不會(huì)改變引用計(jì)數(shù)值。它被用來(lái)打破依賴循環(huán)(想象在一個(gè)tree結(jié)構(gòu)中,父節(jié)點(diǎn)通過(guò)一個(gè)共享所有權(quán)的引 用(chared_ptr)引用子節(jié)點(diǎn),同時(shí)子節(jié)點(diǎn)又必須持有父節(jié)點(diǎn)的引用。如果這第二個(gè)引用也共享所有權(quán),就會(huì)導(dǎo)致一個(gè)循環(huán),最終兩個(gè)節(jié)點(diǎn)內(nèi)存都無(wú)法釋 放)。

  另一方面,auto_ptr已經(jīng)被廢棄,不會(huì)再使用了。

  什么時(shí)候使用unique_ptr,什么時(shí)候使用shared_ptr取決于對(duì)所有權(quán)的需求,我建議閱讀以下的討 論:http://stackoverflow.com/questions/15648844/using-smart-pointers-for- class-members

  以下第一個(gè)例子使用了unique_ptr。如果你想把對(duì)象所有權(quán)轉(zhuǎn)移給另一個(gè)unique_ptr,需要使用std::move(我會(huì)在最后幾段討論這個(gè)函數(shù))。在所有權(quán)轉(zhuǎn)移后,交出所有權(quán)的智能指針將為空,get()函數(shù)將返回nullptr。

  void foo(int* p) { std::cout << *p << std::endl; } std::unique_ptr p1(new int(42)); std::unique_ptr p2 = std::move(p1); // transfer ownership if(p1) foo(p1.get()); (*p2)++; if(p2) foo(p2.get());

  第二個(gè)例子展示了shared_ptr。用法相似,但語(yǔ)義不同,此時(shí)所有權(quán)是共享的。

  void foo(int* p) { } void bar(std::shared_ptr p) { ++(*p); } std::shared_ptr p1(new int(42)); std::shared_ptr p2 = p1; bar(p1); foo(p2.get());

  第一個(gè)聲明和以下這行是等價(jià)的:

  auto p3 = std::make_shared(42);

  make_shared是一個(gè)非成員函數(shù),使用它的好處是可以一次性分配共享對(duì)象和智能指針自身的內(nèi)存。而顯示地使用 shared_ptr構(gòu)造函數(shù)來(lái)構(gòu)造則至少需要兩次內(nèi)存分配。除了會(huì)產(chǎn)生額外的開(kāi)銷,還可能會(huì)導(dǎo)致內(nèi)存泄漏。在下面這個(gè)例子中,如果seed()拋出一個(gè) 錯(cuò)誤就會(huì)產(chǎn)生內(nèi)存泄漏。

  void foo(std::shared_ptr p, int init) { *p = init; } foo(std::shared_ptr(new int(42)), seed());

  如果使用make_shared就不會(huì)有這個(gè)問(wèn)題了。第三個(gè)例子展示了weak_ptr。注意,你必須調(diào)用lock()來(lái)獲得被引用對(duì)象的shared_ptr,通過(guò)它才能訪問(wèn)這個(gè)對(duì)象。

  auto p = std::make_shared(42); std::weak_ptr wp = p; { auto sp = wp.lock(); std::cout << *sp << std::endl; } p.reset(); if(wp.expired()) std::cout << "expired" << std::endl;

  如果你試圖鎖定(lock)一個(gè)過(guò)期(指被弱引用對(duì)象已經(jīng)被釋放)的weak_ptr,那你將獲得一個(gè)空的shared_ptr.


Lambdas (省去了 寫大量的函數(shù)對(duì)象)

?????? 思想:函數(shù)就近使用原則.

  匿名函數(shù)(也叫l(wèi)ambda)已經(jīng)加入到C++中,并很快異軍突起。這個(gè)從函數(shù)式編程中借來(lái)的強(qiáng)大特性,使很多其他特性以及類庫(kù)得以實(shí)現(xiàn)。你可以在 任何使用函數(shù)對(duì)象或者函子(functor)或std::function的地方使用lambda。你可以從這里 (http://msdn.microsoft.com/en-us/library/dd293603.aspx)找到語(yǔ)法說(shuō)明。

std::vector v; v.push_back(1); v.push_back(2); v.push_back(3); std::for_each(std::begin(v), std::end(v), [](int n) {std::cout << n << std::endl;}); auto is_odd = [](int n) {return n%2==1; }; auto pos = std::find_if(std::begin(v), std::end(v), is_odd); if(pos != std::end(v)) std::cout << *pos << std::endl;

  更復(fù)雜的是遞歸lambda。考慮一個(gè)實(shí)現(xiàn)Fibonacci函數(shù)的lambda。如果你試圖用auto來(lái)聲明,就會(huì)得到一個(gè)編譯錯(cuò)誤


Move semantics (Move語(yǔ)義)

??????? 移動(dòng)語(yǔ)義避免了移動(dòng)原始數(shù)據(jù),只是修改了記錄...

  這是C++11中所涵蓋的另一個(gè)重要話題。就這個(gè)話題可以寫出一系列文章,僅用一個(gè)段落來(lái)說(shuō)明顯然是不夠的。因此在這里我不會(huì)過(guò)多的深入細(xì)節(jié),如果你還不是很熟悉這個(gè)話題,我鼓勵(lì)你去地資料。

  C++11加入了右值引用(rvalue reference)的概念(用&&標(biāo)識(shí)),用來(lái)區(qū)分對(duì)左值和右值的引用。左值就是一個(gè)有名字的對(duì)象,而右值則是一個(gè)無(wú)名對(duì)象(臨時(shí)對(duì) 象)。move語(yǔ)義允許修改右值(以前右值被看作是不可修改的,等同于const T&類型)。

  C++的class或者struct以前都有一些隱含的成員函數(shù):默認(rèn)構(gòu)造函數(shù)(僅當(dāng)沒(méi)有顯示定義任何其他構(gòu)造函數(shù)時(shí)才存在),拷貝構(gòu)造函數(shù),析構(gòu) 函數(shù)還有拷貝賦值操作符。拷貝構(gòu)造函數(shù)和拷貝賦值操作符提供bit-wise的拷貝(淺拷貝),也就是逐個(gè)bit拷貝對(duì)象。也就是說(shuō),如果你有一個(gè)類包含 指向其他對(duì)象的指針,拷貝時(shí)只會(huì)拷貝指針的值而不會(huì)管指向的對(duì)象。在某些情況下這種做法是沒(méi)問(wèn)題的,但在很多情況下,實(shí)際上你需要的是深拷貝,也就是說(shuō)你 希望拷貝指針?biāo)赶虻膶?duì)象。而不是拷貝指針的值。這種情況下,你需要顯示地提供拷貝構(gòu)造函數(shù)與拷貝賦值操作符來(lái)進(jìn)行深拷貝。

  如果你用來(lái)初始化或拷貝的源對(duì)象是個(gè)右值(臨時(shí)對(duì)象)會(huì)怎么樣呢?你仍然需要拷貝它的值,但隨后很快右值就會(huì)被釋放。這意味著產(chǎn)生了額外的操作開(kāi)銷,包括原本并不需要的空間分配以及內(nèi)存拷貝。

  現(xiàn)在說(shuō)說(shuō)move constructor和move assignment operator。這兩個(gè)函數(shù)接收T&&類型的參數(shù),也就是一個(gè)右值。在這種情況下,它們可以修改右值對(duì)象,例如“偷走”它們內(nèi)部指針?biāo)?指向的對(duì)象。舉個(gè)例子,一個(gè)容器的實(shí)現(xiàn)(例如vector或者queue)可能包含一個(gè)指向元素?cái)?shù)組的指針。當(dāng)用一個(gè)臨時(shí)對(duì)象初始化一個(gè)對(duì)象時(shí),我們不需 要分配另一個(gè)數(shù)組,從臨時(shí)對(duì)象中把值復(fù)制過(guò)來(lái),然后在臨時(shí)對(duì)象析構(gòu)時(shí)釋放它的內(nèi)存。我們只需要將指向數(shù)組內(nèi)存的指針值復(fù)制過(guò)來(lái),由此節(jié)約了一次內(nèi)存分配, 一次元數(shù)組的復(fù)制以及后來(lái)的內(nèi)存釋放。



總結(jié)

以上是生活随笔為你收集整理的几个方便编程的C++特性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。