自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊我常用的10個(gè)C++新特性

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

[[405800]]

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

下面是正文:

auto類型推導(dǎo)

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

  1. auto a = 10; // 10是int型,可以自動(dòng)推導(dǎo)出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可以通過=右邊的類型推導(dǎo)出變量的類型。

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

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

智能指針

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

那什么時(shí)候使用std::shared_ptr,什么時(shí)候使用std::unique_ptr呢?

  • 當(dāng)所有權(quán)不明晰的情況,有可能多個(gè)對(duì)象共同管理同一塊內(nèi)存時(shí),要使用std::shared_ptr;
  • 而std::unique_ptr強(qiáng)調(diào)的是獨(dú)占,同一時(shí)刻只能有一個(gè)對(duì)象占用這塊內(nèi)存,不支持多個(gè)對(duì)象共同管理同一塊內(nèi)存。

兩類智能指針使用方式類似,拿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不允許移動(dòng),編譯失敗 
  17.    ptr->Print(); 
  18.    return 0; 

std::lock相關(guān)

C++11提供了兩種鎖封裝,通過RAII方式可動(dòng)態(tài)的釋放鎖資源,防止編碼失誤導(dǎo)致始終持有鎖。

這兩種封裝是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,因?yàn)閟td::lock_guard更加輕量級(jí),但如果用在條件變量的wait中環(huán)境中,必須使用std::unique_lock。

條件變量

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

這里使用條件變量實(shí)現(xiàn)一個(gè)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. }; 

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

原子操作

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

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

多線程

什么是多線程這里就不過多介紹,新特性關(guān)于多線程最主要的就是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在其對(duì)象生命周期結(jié)束時(shí)必須要調(diào)用join()或者detach(),否則程序會(huì)terminate(),這個(gè)問題在C++20中的std::jthread得到解決,但是C++20現(xiàn)在多數(shù)編譯器還沒有完全支持所有特性,先暫時(shí)了解下即可,項(xiàng)目中沒必要著急使用。

左值右值移動(dòng)語義相關(guān)

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

關(guān)于左值和右值,有兩種方式理解:

概念1:

左值:可以放到等號(hào)左邊的東西叫左值。

右值:不可以放到等號(hào)左邊的東西就叫右值。

概念2:

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

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

舉例來說:

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

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

左值一般有:

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

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

運(yùn)算表達(dá)式產(chǎn)生的臨時(shí)變量、不和對(duì)象關(guān)聯(lián)的原始字面量、非引用返回的臨時(shí)變量、lambda表達(dá)式等都是純右值。例如:

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

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

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

這塊的概念太多了,涉及很多知識(shí)點(diǎn),這里不太展開介紹了,具體可以看這篇文章:《左值引用、右值引用、移動(dòng)語義、完美轉(zhuǎn)發(fā),你知道的不知道的都在這里》

std::function和lambda表達(dá)式

這兩個(gè)可以說是我最常用的特性,使用它們會(huì)讓函數(shù)的調(diào)用相當(dāng)方便。使用std::function可以完全替代以前那種繁瑣的函數(shù)指針形式。

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

  1. std::function<void(int)> f; // 這里表示function的對(duì)象f的參數(shù)是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.    // 存儲(chǔ)自由函數(shù) 
  19.    std::function<void(int)> f_display = print_num; 
  20.    f_display(-9); 
  21.  
  22.    // 存儲(chǔ) lambda 
  23.    std::function<void()> f_display_42 = []() { print_num(42); }; 
  24.    f_display_42(); 
  25.  
  26.    // 存儲(chǔ)到 std::bind 調(diào)用的結(jié)果 
  27.    std::function<void()> f_display_31337 = std::bind(print_num, 31337); 
  28.    f_display_31337(); 
  29.  
  30.    // 存儲(chǔ)到成員函數(shù)的調(diào)用 
  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.    // 存儲(chǔ)到數(shù)據(jù)成員訪問器的調(diào)用 
  37.    std::function<int(Foo const&)> f_num = &Foo::num_; 
  38.    std::cout << "num_: " << f_num(foo) << '\n'
  39.  
  40.    // 存儲(chǔ)到成員函數(shù)及對(duì)象的調(diào)用 
  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.    // 存儲(chǔ)到成員函數(shù)和對(duì)象指針的調(diào)用 
  46.    std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1); 
  47.    f_add_display3(3); 
  48.  
  49.    // 存儲(chǔ)到函數(shù)對(duì)象的調(diào)用 
  50.    std::function<void(int)> f_display_obj = PrintNum(); 
  51.    f_display_obj(18); 

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

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

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

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

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

  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使得我們平時(shí)編程過程中封裝函數(shù)更加的方便,而lambda表達(dá)式將這種方便發(fā)揮到了極致,可以在需要的時(shí)間就地定義匿名函數(shù),不再需要定義類或者函數(shù)等,在自定義STL規(guī)則時(shí)候也非常方便,讓代碼更簡潔,更靈活,提高開發(fā)效率。

std::file_system

C++17正式將file_system納入標(biāo)準(zhǔn)中,提供了關(guān)于文件的大多數(shù)功能,基本上應(yīng)有盡有,這里簡單舉幾個(gè)例子:

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

std::chrono

chrono很強(qiáng)大,也是我常用的功能,平時(shí)的打印函數(shù)耗時(shí),休眠某段時(shí)間等,我都是使用chrono。

在C++11中引入了duration、time_point和clocks,在C++20中還進(jìn)一步支持了日期和時(shí)區(qū)。這里簡要介紹下C++11中的這幾個(gè)新特性。

duration

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

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

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

  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表示一種數(shù)值類型,用來表示Period的數(shù)量,比如int、float、double,Period是ratio類型,用來表示【用秒表示的時(shí)間單位】比如second,常用的duration已經(jīng)定義好了,在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表示一個(gè)分?jǐn)?shù),我們可以自定義Period,比如ratio<2, 1>表示單位時(shí)間是2秒。

time_point

表示一個(gè)具體時(shí)間點(diǎn),如2020年5月10日10點(diǎn)10分10秒,拿獲取當(dāng)前時(shí)間舉例:

  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為高精度時(shí)鐘,下面會(huì)提到 

clocks

時(shí)鐘,chrono里面提供了三種時(shí)鐘:

  • steady_clock
  • system_clock
  • high_resolution_clock

steady_clock

穩(wěn)定的時(shí)間間隔,表示相對(duì)時(shí)間,相對(duì)于系統(tǒng)開機(jī)啟動(dòng)的時(shí)間,無論系統(tǒng)時(shí)間如何被更改,后一次調(diào)用now()肯定比前一次調(diào)用now()的數(shù)值大,可用于計(jì)時(shí)。

system_clock

表示當(dāng)前的系統(tǒng)時(shí)鐘,可以用于獲取當(dāng)前時(shí)間:

  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表示系統(tǒng)可用的最高精度的時(shí)鐘,實(shí)際上就是system_clock或者steady_clock其中一種的定義,官方?jīng)]有說明具體是哪個(gè),不同系統(tǒng)可能不一樣,我之前看gcc chrono源碼中high_resolution_clock是steady_clock的typedef。

 

責(zé)任編輯:武曉燕 來源: 程序喵大人
相關(guān)推薦

2013-12-30 10:42:42

C++特性

2018-05-18 15:05:25

JavaJava 10新特性

2024-02-04 15:58:53

C++ 17編程代碼

2013-07-29 11:11:33

C++C++11

2010-01-14 10:56:43

Visual C++

2024-07-10 18:51:52

2021-03-06 08:10:16

Redis6 Java架構(gòu)分布式框架

2012-06-13 10:26:21

iOS 6

2010-01-26 17:44:32

Visual C++開

2009-08-19 09:38:34

C++編程

2020-07-27 08:05:56

C++語言后端

2021-08-19 08:31:46

云計(jì)算

2009-08-18 17:03:49

C#3.5新特性

2019-03-05 15:03:09

Android Q安卓系統(tǒng)功能

2025-01-13 12:30:00

C++開發(fā)編譯

2019-10-29 05:47:15

CC++Python

2010-01-25 18:19:17

C++特性

2010-01-25 18:19:17

C++特性

2010-01-25 18:19:17

C++特性

2015-08-27 16:15:26

Windwos 10特性
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)