午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

C++11/14/17...

 碼農(nóng)書館 2021-02-09

目錄

 

環(huán)境準(zhǔn)備

被棄用的特性

常量字符串賦值需要使用const char*

與C的兼容性

語言可用性的強(qiáng)化

類型推導(dǎo)

區(qū)間迭代

 列表初始化

 模板增強(qiáng)

面對對象增強(qiáng)

語言運(yùn)行期的強(qiáng)化

Lambda表達(dá)式

std::function

std::bind/std::placeholder

右值引用

新增容器

智能指針和引用計(jì)數(shù)

RAII與引用計(jì)數(shù)

std::shared_ptr

std::unique_ptr

std::shared_ptr仍然無法解決的問題


環(huán)境準(zhǔn)備

在IDE工具中選擇編譯器,加入編譯命令 -std=c++11


被棄用的特性

(棄用暗示避免使用,但仍是標(biāo)準(zhǔn)庫的一部分)

  • 常量字符串賦值需要使用const char*

char* str = "Hello world!";

這里的char*和const char*都是指向一個(gè)常量字符串,如果有另外一個(gè)char* str2指向的常量字符串和str一模一樣,那么其實(shí)str和str2也的地址是完全相同的,這有點(diǎn)類似java的常量池。

  • auto_ptr 被棄用,應(yīng)使用 unique_ptr。
  1. #include<iostream>
  2. #include<memory>

  3. using namespace std;

  4. class A
  5. {
  6. public:
  7. A()
  8. {
  9. cout << "A()";
  10. }
  11. ~A()
  12. {
  13. cout << "~A()";
  14. }
  15. };

  16. int main()
  17. {
  18. auto_ptr<A> global;
  19. {
  20. cout << "Test1\n";
  21. auto_ptr<A> a(new A());
  22. }
  23. {
  24. cout << "\nTest2\n";
  25. A* b = new A();
  26. auto_ptr<A> a(b);
  27. global.reset(b);
  28. auto_ptr<A> c(b);
  29. }
  30. {
  31. cout << "\nTest3\n";
  32. A*b = new A[5];
  33. auto_ptr<A> a(b);
  34. }
  35. {
  36. cout << "\nTest3\n";
  37. unique_ptr<A> a(new A[5]);
  38. }
  39. cout << "\nEnd\n";
  40. system("pause");
  41. }

auto_ptr和unique_ptr的構(gòu)造函數(shù)都聲明為explicit,為了避免不知情的情況下出現(xiàn)的錯(cuò)誤,不能存在隱式轉(zhuǎn)換。

  1. std::auto_ptr<A> a = new A(); //編譯錯(cuò)誤
  2. std::auto_ptr<A> a(new A()); //編譯成功

關(guān)于explicit 更詳細(xì)的解釋 https://www.cnblogs.com/cutepig/archive/2009/01/14/1375917.html

auto_ptr和unique_ptr一樣不能處理數(shù)組,因?yàn)樗鼈兾鰳?gòu)的時(shí)候,都只是delete ptr,而不是delete []ptr。

  •  register 關(guān)鍵字被棄用。
  •  C 語言風(fēng)格的類型轉(zhuǎn)換被棄用,應(yīng)該使用 static_castreinterpret_cast、const_cast 來進(jìn)行類型轉(zhuǎn)換

與C的兼容性

C++不是C的一個(gè)超集,在編寫C++時(shí),也應(yīng)該盡可能地避免諸如void *之類的程序風(fēng)格,而在不得不使用C時(shí),應(yīng)該使用extern "C"這種特性,將C語言的代碼與C++代碼進(jìn)行分離編譯,再統(tǒng)一鏈接這種做法。

https://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html


語言可用性的強(qiáng)化

nullptr用來區(qū)分空指針和0,和傳統(tǒng)C++會(huì)把NULL、0視為同一種東西,這會(huì)在C++中重載特性中發(fā)生混亂。

constexpr用來修飾一段代碼,說明該函數(shù)在編譯時(shí)便一定是個(gè)常數(shù),便于編譯器優(yōu)化。

  1. // constexpr 聲明factorial可以參與編譯期的運(yùn)算
  2. constexpr int factorial(int n)
  3. {
  4. return n <= 1? 1 : (n * factorial(n - 1));
  5. }
  6. int main()
  7. {
  8. std::cout << "4! = " ;
  9. constN<factorial(4)> out1; // computed at compile time

  10. volatile int k = 8; // disallow optimization using volatile
  11. std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
  12. }

類型推導(dǎo)

C++11引入了auto和decltype

  1. auto x = 1;
  2. auto y = 2;
  3. decltype(x+y) z;

  4. //尾返回類型
  5. template<typename T, typename U>
  6. auto add(T x, U y) -> decltype(x+y) {
  7. return x+y;
  8. }


  9. //C++直接支持
  10. template<typename T, typename U>
  11. auto add(T x, U y) {
  12. return x+y;
  13. }

區(qū)間迭代

  1. int array[] = {1,2,3,4,5};
  2. for(auto &x : array) {
  3. std::cout << x << std::endl;
  4. }


  5. //std::vector

  6. //原來
  7. int array[] = {1,2,3,4,5};
  8. for(auto &x : array) {
  9. std::cout << x << std::endl;
  10. }

  11. //現(xiàn)在
  12. // & 啟用了引用, 如果沒有則對 arr 中的元素只能讀取不能修改
  13. for(auto &i : arr) {
  14. std::cout << i << std::endl;
  15. }

 列表初始化

可以用一種統(tǒng)一的方式對數(shù)組,結(jié)構(gòu)體,類和所有STL容器進(jìn)行初始化。

  1. #include<iostream>
  2. #include<map>
  3. #include<list>
  4. #include<vector>

  5. using namespace std;

  6. struct Foo
  7. {
  8. int x;
  9. int y;
  10. Foo(int, int){ cout << "Foo construction"; }
  11. };
  12. int main()
  13. {
  14. int arr[] = { 1, 2, 3, 4, 5 };
  15. std::map < int, int > map_t { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
  16. std::list<std::string> list_str{ "hello", "world", "china" };
  17. std::vector<double> vec_d { 0.0,0.1,0.2,0.3,0.4,0.5};
  18. Foo foo{1,2};
  19. for(auto& x : vec_d)
  20. {
  21. std::cout<<x<<" ";
  22. }
  23. std::cout<<"\n";
  24. }

也可以列表初始化構(gòu)造函數(shù),列表還可以作為普通函數(shù)的形參。

  1. #include <initializer_list>

  2. class Magic {
  3. public:
  4. Magic(std::initializer_list<int> list) {}
  5. };

  6. Magic magic = {1,2,3,4,5};
  7. std::vector<int> v = {1, 2, 3, 4}

  8. void func(std::initializer_list<int> list) {
  9. return;
  10. }

  11. func({1,2,3});

統(tǒng)一的語法來初始化任意對象

  1. struct A {
  2. int a;
  3. float b;
  4. };
  5. struct B {

  6. B(int _a, float _b): a(_a), b(_b) {}
  7. private:
  8. int a;
  9. float b;
  10. };

  11. A a {1, 1.1}; // 統(tǒng)一的初始化語法
  12. B b {2, 2.2};

 模板增強(qiáng)

  • 尖括號(hào) ">"

在傳統(tǒng) C++ 的編譯器中,>>一律被當(dāng)做右移運(yùn)算符來進(jìn)行處理。但實(shí)際上我們很容易就寫出了嵌套模板的代碼:

std::vector<std::vector<int>> wow;

這在傳統(tǒng)C++編譯器下是不能夠被編譯的,而 C++11 開始,連續(xù)的右尖括號(hào)將變得合法,并且能夠順利通過編譯。

  •  類型別名模板

在了解類型別名模板之前,需要理解『模板』和『類型』之間的不同。仔細(xì)體會(huì)這句話:模板是用來產(chǎn)生類型的。在傳統(tǒng) C++中,typedef可以為類型定義一個(gè)新的名稱,但是卻沒有辦法為模板定義一個(gè)新的名稱。因?yàn)椋0宀皇穷愋?。例如?/p>

  1. template< typename T, typename U, int value>
  2. class SuckType {
  3. public:
  4. T a;
  5. U b;
  6. SuckType():a(value),b(value){}
  7. };
  8. template< typename U>
  9. typedef SuckType<std::vector<int>, U, 1> NewType; // 不合法

C++11 使用 using 引入了下面這種形式的寫法,并且同時(shí)支持對傳統(tǒng) typedef 相同的功效:

通常我們使用 typedef 定義別名的語法是:typedef 原名稱 新名稱;,但是對函數(shù)指針等別名的定義語法卻不相同,這通常給直接閱讀造成了一定程度的困難。

  1. typedef int (*process)(void *); // 定義了一個(gè)返回類型為 int,參數(shù)為 void* 的函數(shù)指針類型,名字叫做 process
  2. using process = int(*)(void *); // 同上, 更加直觀

  3. template <typename T>
  4. using NewType = SuckType<int, T, 1>; // 合法
  • 變長參數(shù)模板
template<typename... TS> class Magic;

  獲取參數(shù)個(gè)數(shù)

  1. template<typename ...Args>
  2. void magic(Args ...args)
  3. {
  4. std::cout << sizeof...(args) << std::endl;
  5. }

對參數(shù)進(jìn)行解包

  1. template<typename T>
  2. void printf(T value)
  3. {
  4. std::cout << value << std::endl;
  5. }

  6. template<typename T, typename ...Args>
  7. void printf(T value, Args... args)
  8. {
  9. std::cout << value << std::endl;
  10. printf(args...);
  11. }

 列表初始化展開

  1. template<typename T, typename... Argsa>
  2. auto print(T value, Args... args)
  3. {
  4. std::cout<<value<<std::endl;
  5. return std::initializer_list<T>
  6. {([&]{std::cout<<args<<std::endl;}(), value)...};
  7. }

變長參數(shù)模板示例,求最大值

  1. #include<iostream>

  2. template<typename T>
  3. T max(T a, T b)
  4. {
  5. if(a>=b)
  6. {
  7. return a;
  8. }
  9. return b;
  10. }

  11. template<typename T,typename... Args>
  12. T max(T a, T b, Args... args)
  13. {
  14. if(a >= b)
  15. {
  16. return max(a, args...);
  17. }
  18. return max(b, args...);
  19. }

  20. int main()
  21. {
  22. std::cout<<max(1,5,3,2,11);
  23. }

模板增強(qiáng)可見https://blog.csdn.net/tennysonsky/article/details/77389891 


面對對象增強(qiáng)

  • 委托構(gòu)造,同一個(gè)類中一個(gè)構(gòu)造函數(shù)調(diào)用另一個(gè)構(gòu)造函數(shù)
  • 繼承構(gòu)造,避免參數(shù)傳遞
  • 顯式虛函數(shù)重載,override,final
  • 顯式禁用默認(rèn)函數(shù)

語言運(yùn)行期的強(qiáng)化

Lambda表達(dá)式

  1. auto basicLambda = [] {std::cout << "Hello, world!" <<endl;};
  2. basicLambda();

捕獲分為引用捕獲[&]和值捕獲[=],可以讓編譯器自行推導(dǎo)應(yīng)用列表。

參數(shù)寫在[](參數(shù)),在C++14中類型可以使用auto。

  1. auto process = [&](int a, int b){std::cout<<(a+b)*c<"\n";};
  2. process(a,b);

Lambda表達(dá)式又稱為匿名函數(shù),有時(shí)候也無需指定其名字而直接調(diào)用。

[&](){std::cout<<"Hello world!\n"}();

 

std::function

C++11 std::function是一種通用、多態(tài)的函數(shù)封裝,它的實(shí)例可以對任何可以調(diào)用的目標(biāo)實(shí)體進(jìn)行存儲(chǔ),復(fù)制和調(diào)用操作,它也是一種類型安全的函數(shù)的容器。

  1. #include <functional>
  2. #include <iostream>

  3. int foo(int para) {
  4. return para;
  5. }

  6. int main() {
  7. // std::function 包裝了一個(gè)返回值為 int, 參數(shù)為 int 的函數(shù)
  8. std::function<int(int)> func = foo;

  9. int important = 10;
  10. std::function<int(int)> func2 = [&](int value){
  11. return 1 + value + important;
  12. };
  13. std::cout << func(10) << std::endl;
  14. std::cout << func2(10) << std::endl;
  15. }

std::bind/std::placeholder

  1. #include<functional>

  2. int foo(int a, int b, int c)
  3. {
  4. }

  5. int main()
  6. {
  7. //std::placeholders::_1表示對第一個(gè)參數(shù)占位
  8. auto bindFoo = std::bind(foo, std::placeholders::_1, 1, 2);
  9. bindFoo(1);
  10. }

右值引用

右值引用(及其支持的Move語意和完美轉(zhuǎn)發(fā))是C++11加入的重大語言特性之一。從實(shí)踐角度講,它能夠完美解決C++

中長久以來為人詬病的臨時(shí)對象效率問題。從語言本身講,它健全了C++中的引用類型在左值右值方面的缺陷。

為了測試,在編譯時(shí)設(shè)置編譯選項(xiàng)

-fno-elide-constructors
  1. class A
  2. {
  3. public:
  4. A() { std::cout << "Constructor" << std::endl; }
  5. A(const A&) { std::cout << "Copy Constructor" << std::endl; }
  6. ~A() {}
  7. };

  8. static A getA()
  9. {
  10. A a;
  11. return a;
  12. }

  13. int main()
  14. {
  15. std::cout<<i<<" "<<j<<"\n";
  16. A a = getA();

  17. return 0;
  18. }

如圖,在這種情況下,調(diào)用了一次構(gòu)造函數(shù),return時(shí)調(diào)用了一次拷貝構(gòu)造函數(shù)生成了一個(gè)臨時(shí)的a,將它return回的時(shí)候返回給了main函數(shù)中的a,隨機(jī)這個(gè)臨時(shí)的a也就消失了。這個(gè)階段浪費(fèi)了不少的性能。

A &&a = getA();

但如果將它改成了右值引用,就只會(huì)調(diào)用一次拷貝構(gòu)造函數(shù)用于生成臨時(shí)的變量,臨時(shí)的變量生命周期和右值引用的生命周期相等。

還有有關(guān)右值引用與深拷貝和轉(zhuǎn)發(fā)詳細(xì)可以參見https://www.cnblogs.com/qicosmos/p/4283455.html


新增容器


智能指針和引用計(jì)數(shù)

RAII與引用計(jì)數(shù)

引用計(jì)數(shù)這種計(jì)數(shù)是為了防止內(nèi)存泄露而產(chǎn)生的?;鞠敕ㄊ菍τ趧?dòng)態(tài)分配的對象,進(jìn)行引用計(jì)數(shù),每當(dāng)增加一次對同一個(gè)對象的引用,那么引用對象的引用計(jì)數(shù)就會(huì)增加一次,每刪除一次引用,引用計(jì)數(shù)就會(huì)減一,當(dāng)一個(gè)對象的引用計(jì)數(shù)減為零時(shí),就自動(dòng)刪除指向的堆內(nèi)存。

引用計(jì)數(shù)不是垃圾回收,引用技術(shù)能夠盡快收回不再被使用的對象,同時(shí)在回收的過程中也不會(huì)造成長時(shí)間的等待,更能夠清晰明確的表明資源的生命周期。

std::shared_ptr

  1. auto pointer = std::make_shared<int>(10);
  2. auto pointer2 = pointer;
  3. auto pointer3 = pointer;
  4. int *p = pointer.get(); //這樣不會(huì)增加引用計(jì)數(shù)

  5. pointer2.reset();
  6. pointer3.reset();

  7. std::cout<<pointer.use_count()<<std::endl;

std::unique_ptr

獨(dú)占指針,類似于之前的auto_ptr,

std::shared_ptr仍然無法解決的問題

  1. #include <iostream>
  2. #include <memory>

  3. class A;
  4. class B;

  5. class A {
  6. public:
  7. std::shared_ptr<B> pointer;
  8. ~A() {
  9. std::cout << "A 被銷毀" << std::endl;
  10. }
  11. };
  12. class B {
  13. public:
  14. std::shared_ptr<A> pointer;
  15. ~B() {
  16. std::cout << "B 被銷毀" << std::endl;
  17. }
  18. };
  19. int main() {
  20. std::shared_ptr<A> a = std::make_shared<A>();
  21. std::shared_ptr<B> b = std::make_shared<B>();
  22. a->pointer = b;
  23. b->pointer = a;

  24. return 0;
  25. }

?-¤?¤è??¥?????è?°

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多