成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊我常用的10個C++新特性

開發 后端
這篇文章我會總結一些常用的新特性,這些新特性可以說是必須掌握的!我也不太清楚其他人常用的新特性有啥,這里僅分享下我和身邊朋友們常用的新特性!

[[405800]]

之前文章介紹的是C++11之后所有的新特性,這篇文章我會總結一些常用的新特性,這些新特性可以說是必須掌握的!我也不太清楚其他人常用的新特性有啥,這里僅分享下我和身邊朋友們常用的新特性!

下面是正文:

auto類型推導

auto可以讓編譯器在編譯器就推導出變量的類型,看代碼:

  1. auto a = 10; // 10是int型,可以自動推導出a是int 
  2.  
  3. int i = 10; 
  4. auto b = i; // b是int型 
  5.  
  6. auto d = 2.0; // d是double型 
  7. auto f = []() { // f是啥類型?直接用auto就行 
  8.     return std::string("d"); 

利用auto可以通過=右邊的類型推導出變量的類型。

什么時候使用auto呢?簡單類型其實沒必要使用auto,然而某些復雜類型就有必要使用auto,比如lambda表達式的類型,async函數的類型等,例如:

  1. auto func = [&] {     
  2.     cout << "xxx"
  3. }; // 對于func你難道不使用auto嗎,反正我是不關心lambda表達式究竟是什么類型。 
  4. auto asyncfunc = std::async(std::launch::async, func); 

智能指針

C++11新特性中主要有兩種智能指針std::shared_ptr和std::unique_ptr。

那什么時候使用std::shared_ptr,什么時候使用std::unique_ptr呢?

  • 當所有權不明晰的情況,有可能多個對象共同管理同一塊內存時,要使用std::shared_ptr;
  • 而std::unique_ptr強調的是獨占,同一時刻只能有一個對象占用這塊內存,不支持多個對象共同管理同一塊內存。

兩類智能指針使用方式類似,拿std::unique_ptr舉例:

  1. using namespace std; 
  2.  
  3. struct A { 
  4.    ~A() { 
  5.        cout << "A delete" << endl; 
  6.    } 
  7.    void Print() { 
  8.        cout << "A" << endl; 
  9.    } 
  10. }; 
  11.  
  12.  
  13. int main() { 
  14.    auto ptr = std::unique_ptr<A>(new A); 
  15.    auto tptr = std::make_unique<A>(); // error, c++11還不行,需要c++14 
  16.    std::unique_ptr<A> tem = ptr; // error, unique_ptr不允許移動,編譯失敗 
  17.    ptr->Print(); 
  18.    return 0; 

std::lock相關

C++11提供了兩種鎖封裝,通過RAII方式可動態的釋放鎖資源,防止編碼失誤導致始終持有鎖。

這兩種封裝是std::lock_guard和std::unique_lock,使用方式類似,看下面的代碼:

  1. #include <iostream> 
  2. #include <mutex> 
  3. #include <thread> 
  4. #include <chrono> 
  5.  
  6. using namespace std; 
  7. std::mutex mutex_; 
  8.  
  9. int main() { 
  10.    auto func1 = [](int k) { 
  11.        // std::lock_guard<std::mutex> lock(mutex_); 
  12.        std::unique_lock<std::mutex> lock(mutex_); 
  13.        for (int i = 0; i < k; ++i) { 
  14.            cout << i << " "
  15.       } 
  16.        cout << endl; 
  17.   }; 
  18.    std::thread threads[5]; 
  19.    for (int i = 0; i < 5; ++i) { 
  20.        threads[i] = std::thread(func1, 200); 
  21.   } 
  22.    for (auto& th : threads) { 
  23.        th.join(); 
  24.   } 
  25.    return 0; 

普通情況下建議使用std::lock_guard,因為std::lock_guard更加輕量級,但如果用在條件變量的wait中環境中,必須使用std::unique_lock。

條件變量

條件變量是C++11引入的一種同步機制,它可以阻塞一個線程或多個線程,直到有線程通知或者超時才會喚醒正在阻塞的線程,條件變量需要和鎖配合使用,這里的鎖就是上面介紹的std::unique_lock。

這里使用條件變量實現一個CountDownLatch:

  1. class CountDownLatch { 
  2.    public
  3.     explicit CountDownLatch(uint32_t count) : count_(count); 
  4.  
  5.     void CountDown() { 
  6.         std::unique_lock<std::mutex> lock(mutex_); 
  7.         --count_; 
  8.         if (count_ == 0) { 
  9.             cv_.notify_all(); 
  10.         } 
  11.     } 
  12.  
  13.     void Await(uint32_t time_ms = 0) { 
  14.         std::unique_lock<std::mutex> lock(mutex_); 
  15.         while (count_ > 0) { 
  16.             if (time_ms > 0) { 
  17.                 cv_.wait_for(lock, std::chrono::milliseconds(time_ms)); 
  18.             } else { 
  19.                 cv_.wait(lock); 
  20.             } 
  21.         } 
  22.     } 
  23.  
  24.     uint32_t GetCount() const { 
  25.         std::unique_lock<std::mutex> lock(mutex_); 
  26.       return count_; 
  27.     } 
  28.  
  29.    private: 
  30.     std::condition_variable cv_; 
  31.     mutable std::mutex mutex_; 
  32.     uint32_t count_ = 0; 
  33. }; 

條件變量還有幾個坑,可以看這篇文章:《使用條件變量的坑你知道嗎》

原子操作

C++11提供了原子類型std::atomic,用于原子操作,使用這種方式既可以保證線程安全,也不需要使用鎖來進行臨界區保護,對一些普通變量來說尤其方便,看代碼:

  1. std::atomic<int> atomicInt; 
  2. atomicInt++; 
  3. atomicInt--; 
  4. atomicInt.store(2); 
  5. int value = atomicInt.load(); 

多線程

什么是多線程這里就不過多介紹,新特性關于多線程最主要的就是std::thread的使用,它的使用也很簡單,看代碼:

  1. #include <iostream> 
  2. #include <thread> 
  3.  
  4. using namespace std; 
  5.  
  6. int main() { 
  7.    auto func = []() { 
  8.        for (int i = 0; i < 10; ++i) { 
  9.            cout << i << " "
  10.       } 
  11.        cout << endl; 
  12.   }; 
  13.    std::thread t(func); 
  14.    if (t.joinable()) { 
  15.        t.detach(); 
  16.   } 
  17.    auto func1 = [](int k) { 
  18.        for (int i = 0; i < k; ++i) { 
  19.            cout << i << " "
  20.       } 
  21.        cout << endl; 
  22.   }; 
  23.    std::thread tt(func1, 20); 
  24.    if (tt.joinable()) { // 檢查線程可否被join 
  25.        tt.join(); 
  26.   } 
  27.    return 0; 

這里記住,std::thread在其對象生命周期結束時必須要調用join()或者detach(),否則程序會terminate(),這個問題在C++20中的std::jthread得到解決,但是C++20現在多數編譯器還沒有完全支持所有特性,先暫時了解下即可,項目中沒必要著急使用。

左值右值移動語義相關

大家可能都聽說過左值右值,但可能會有部分讀者還沒有搞清楚這些概念。這里解惑下:

關于左值和右值,有兩種方式理解:

概念1:

左值:可以放到等號左邊的東西叫左值。

右值:不可以放到等號左邊的東西就叫右值。

概念2:

左值:可以取地址并且有名字的東西就是左值。

右值:不能取地址的沒有名字的東西就是右值。

舉例來說:

  1. int a = b + c 
  2. int d = 4; // d是左值,4作為普通字面量,是右值 

a是左值,有變量名,可以取地址,也可以放到等號左邊, 表達式b+c的返回值是右值,沒有名字且不能取地址,&(b+c)不能通過編譯,而且也不能放到等號左邊。

左值一般有:

  • 函數名和變量名
  • 返回左值引用的函數調用
  • 前置自增自減表達式++i、--i
  • 由賦值表達式或賦值運算符連接的表達式(a=b, a += b等)
  • 解引用表達式*p
  • 字符串字面值"abcd"

介紹右值前需要先介紹兩個概念:純右值和將亡值。

運算表達式產生的臨時變量、不和對象關聯的原始字面量、非引用返回的臨時變量、lambda表達式等都是純右值。例如:

  • 除字符串字面值外的字面值
  • 返回非引用類型的函數調用
  • 后置自增自減表達式i++、i--
  • 算術表達式(a+b, a*b, a&&b, a==b等)
  • 取地址表達式等(&a)

而將亡值是指C++11新增的和右值引用相關的表達式,通常指將要被移動的對象、T&&函數的返回值、std::move函數的返回值、轉換為T&&類型轉換函數的返回值,將亡值可以理解為即將要銷毀的值,通過“盜取”其它變量內存空間方式獲取的值,在確保其它變量不再被使用或者即將被銷毀時,可以避免內存空間的釋放和分配,延長變量值的生命周期,常用來完成移動構造或者移動賦值的特殊任務。例如:

  1. class A { 
  2.     xxx; 
  3. }; 
  4. A a; 
  5. auto c = std::move(a); // c是將亡值 
  6. auto d = static_cast<A&&>(a); // d是將亡值 

這塊的概念太多了,涉及很多知識點,這里不太展開介紹了,具體可以看這篇文章:《左值引用、右值引用、移動語義、完美轉發,你知道的不知道的都在這里》

std::function和lambda表達式

這兩個可以說是我最常用的特性,使用它們會讓函數的調用相當方便。使用std::function可以完全替代以前那種繁瑣的函數指針形式。

還可以結合std::bind一起使用,直接看一段示例代碼:

  1. std::function<void(int)> f; // 這里表示function的對象f的參數是int,返回值是void 
  2. #include <functional> 
  3. #include <iostream> 
  4.  
  5. struct Foo { 
  6.    Foo(int num) : num_(num) {} 
  7.    void print_add(int i) const { std::cout << num_ + i << '\n'; } 
  8.    int num_; 
  9. }; 
  10.  
  11. void print_num(int i) { std::cout << i << '\n'; } 
  12.  
  13. struct PrintNum { 
  14.    void operator()(int i) const { std::cout << i << '\n'; } 
  15. }; 
  16.  
  17. int main() { 
  18.    // 存儲自由函數 
  19.    std::function<void(int)> f_display = print_num; 
  20.    f_display(-9); 
  21.  
  22.    // 存儲 lambda 
  23.    std::function<void()> f_display_42 = []() { print_num(42); }; 
  24.    f_display_42(); 
  25.  
  26.    // 存儲到 std::bind 調用的結果 
  27.    std::function<void()> f_display_31337 = std::bind(print_num, 31337); 
  28.    f_display_31337(); 
  29.  
  30.    // 存儲到成員函數的調用 
  31.    std::function<void(const Foo&, int)> f_add_display = &Foo::print_add; 
  32.    const Foo foo(314159); 
  33.    f_add_display(foo, 1); 
  34.    f_add_display(314159, 1); 
  35.  
  36.    // 存儲到數據成員訪問器的調用 
  37.    std::function<int(Foo const&)> f_num = &Foo::num_; 
  38.    std::cout << "num_: " << f_num(foo) << '\n'
  39.  
  40.    // 存儲到成員函數及對象的調用 
  41.    using std::placeholders::_1; 
  42.    std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1); 
  43.    f_add_display2(2); 
  44.  
  45.    // 存儲到成員函數和對象指針的調用 
  46.    std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1); 
  47.    f_add_display3(3); 
  48.  
  49.    // 存儲到函數對象的調用 
  50.    std::function<void(int)> f_display_obj = PrintNum(); 
  51.    f_display_obj(18); 

從上面可以看到std::function的使用方法,當給std::function填入合適的參數表和返回值后,它就變成了可以容納所有這一類調用方式的函數封裝器。std::function還可以用作回調函數,或者在C++里如果需要使用回調那就一定要使用std::function,特別方便,這方面的使用方式大家可以讀下我之前的文章《搞定c++11新特性std::function和lambda表達式》

lambda表達式可以說是C++11引入的最重要的特性之一,它定義了一個匿名函數,可以捕獲一定范圍的變量在函數內部使用,一般有如下語法形式:

  1. auto func = [capture] (params) opt -> ret { func_body; }; 

其中func是可以當作lambda表達式的名字,作為一個函數使用,capture是捕獲列表,params是參數表,opt是函數選項(mutable之類), ret是返回值類型,func_body是函數體。

看下面這段使用lambda表達式的示例吧:

  1. auto func1 = [](int a) -> int { return a + 1; }; auto func2 = [](int a) { return a + 2; }; cout << func1(1) << " " << func2(2) << endl; 

std::function和std::bind使得我們平時編程過程中封裝函數更加的方便,而lambda表達式將這種方便發揮到了極致,可以在需要的時間就地定義匿名函數,不再需要定義類或者函數等,在自定義STL規則時候也非常方便,讓代碼更簡潔,更靈活,提高開發效率。

std::file_system

C++17正式將file_system納入標準中,提供了關于文件的大多數功能,基本上應有盡有,這里簡單舉幾個例子:

  1. namespace fs = std::filesystem; 
  2. fs::create_directory(dir_path); 
  3. fs::copy_file(src, dst, fs::copy_options::skip_existing); 
  4. fs::exists(filename); 
  5. fs::current_path(err_code); 

file_system之前,想拷貝個文件、獲取文件信息等都需要使用好多C語言API搭配使用才能完成需求,而有了file_system,一切都變得相當簡單。file_system是C++17才引入的新功能,但其實在C++14中就可以使用了,只是file_system在std::experimental空間下。

std::chrono

chrono很強大,也是我常用的功能,平時的打印函數耗時,休眠某段時間等,我都是使用chrono。

在C++11中引入了duration、time_point和clocks,在C++20中還進一步支持了日期和時區。這里簡要介紹下C++11中的這幾個新特性。

duration

std::chrono::duration表示一段時間,常見的單位有s、ms等,示例代碼:

  1. // 拿休眠一段時間舉例,這里表示休眠100ms 
  2. std::this_thread::sleep_for(std::chrono::milliseconds(100)); 

sleep_for里面其實就是std::chrono::duration,表示一段時間,實際是這樣:

  1. typedef duration<int64_t, milli> milliseconds; 
  2. typedef duration<int64_t> seconds; 

duration具體模板如下:

  1. template <class Rep, class Period = ratio<1> > class duration; 

Rep表示一種數值類型,用來表示Period的數量,比如int、float、double,Period是ratio類型,用來表示【用秒表示的時間單位】比如second,常用的duration已經定義好了,在std::chrono::duration下:

  • ratio<3600, 1>:hours
  • ratio<60, 1>:minutes
  • ratio<1, 1>:seconds
  • ratio<1, 1000>:microseconds
  • ratio<1, 1000000>:microseconds
  • ratio<1, 1000000000>:nanosecons

ratio的具體模板如下:

  1. template <intmax_t N, intmax_t D = 1> class ratio; 

N代表分子,D代表分母,所以ratio表示一個分數,我們可以自定義Period,比如ratio<2, 1>表示單位時間是2秒。

time_point

表示一個具體時間點,如2020年5月10日10點10分10秒,拿獲取當前時間舉例:

  1. std::chrono::time_point<std::chrono::high_resolution_clock> Now() { 
  2.    return std::chrono::high_resolution_clock::now(); 
  3. // std::chrono::high_resolution_clock為高精度時鐘,下面會提到 

clocks

時鐘,chrono里面提供了三種時鐘:

  • steady_clock
  • system_clock
  • high_resolution_clock

steady_clock

穩定的時間間隔,表示相對時間,相對于系統開機啟動的時間,無論系統時間如何被更改,后一次調用now()肯定比前一次調用now()的數值大,可用于計時。

system_clock

表示當前的系統時鐘,可以用于獲取當前時間:

  1. int main() { 
  2.    using std::chrono::system_clock; 
  3.    system_clock::time_point today = system_clock::now(); 
  4.    std::time_t tt = system_clock::to_time_t(today); 
  5.    std::cout << "today is: " << ctime(&tt); 
  6.    return 0; 
  7. // today is: Sun May 10 09:48:36 2020 

high_resolution_clock

 

high_resolution_clock表示系統可用的最高精度的時鐘,實際上就是system_clock或者steady_clock其中一種的定義,官方沒有說明具體是哪個,不同系統可能不一樣,我之前看gcc chrono源碼中high_resolution_clock是steady_clock的typedef。

 

責任編輯:武曉燕 來源: 程序喵大人
相關推薦

2018-05-18 15:05:25

JavaJava 10新特性

2013-12-30 10:42:42

C++特性

2024-02-04 15:58:53

C++ 17編程代碼

2021-03-06 08:10:16

Redis6 Java架構分布式框架

2013-07-29 11:11:33

C++C++11

2010-01-14 10:56:43

Visual C++

2024-07-10 18:51:52

2012-06-13 10:26:21

iOS 6

2020-07-27 08:05:56

C++語言后端

2019-03-05 15:03:09

Android Q安卓系統功能

2010-01-26 17:44:32

Visual C++開

2009-08-18 17:03:49

C#3.5新特性

2021-08-19 08:31:46

云計算

2009-08-19 09:38:34

C++編程

2019-10-29 05:47:15

CC++Python

2025-01-13 12:30:00

C++開發編譯

2015-08-27 16:15:26

Windwos 10特性

2009-08-26 17:10:09

C# 3.5新特性

2009-08-31 14:45:07

Visual C# 3

2010-01-25 18:19:17

C++特性
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人欧美一区二区三区黑人孕妇 | 日韩av福利在线观看 | 欧日韩在线| 亚洲综合无码一区二区 | 婷婷在线视频 | 免费观看av| 国产伦精品一区二区三区精品视频 | 鸳鸯谱在线观看高清 | 国产精品久久国产精品 | 久久精品色视频 | 黄瓜av | 天天综合永久入口 | 久久神马 | 丁香综合 | 国产综合久久久 | 中文字幕在线播放不卡 | 99久9| 91精品国产自产在线老师啪 | 国产激情亚洲 | 国产精品精品久久久久久 | 中文字幕一区在线观看视频 | 在线播放国产视频 | 日韩一区二区在线视频 | 亚洲国产精品一区 | 黄色三级免费网站 | 在线观看免费毛片 | 国产精品日日摸夜夜添夜夜av | 日韩精品在线视频 | 亚洲国产欧美国产综合一区 | 亚洲九九 | 91高清视频 | 国产精品视屏 | h视频在线免费观看 | 精品久久久久一区 | www久| 欧美一区二区在线观看 | 亚洲欧洲一区 | 成人毛片视频免费 | 国产一区亚洲二区三区 | 免费一二区 | 免费久久99精品国产婷婷六月 |