日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯網營銷解決方案
聊聊我常用的10個C++新特性

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

成都創(chuàng)新互聯服務項目包括浉河網站建設、浉河網站制作、浉河網頁制作以及浉河網絡營銷策劃等。多年來,我們專注于互聯網行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯網行業(yè)的解決方案,浉河網站推廣取得了明顯的社會效益與經濟效益。目前,我們服務的客戶以成都為中心已經輻射到浉河省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!

下面是正文:

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(new A); 
  15.    auto tptr = std::make_unique(); // error, c++11還不行,需要c++14 
  16.    std::unique_ptr tem = ptr; // error, unique_ptr不允許移動,編譯失敗 
  17.    ptr->Print(); 
  18.    return 0; 

std::lock相關

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

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

 
 
 
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5.  
  6. using namespace std; 
  7. std::mutex mutex_; 
  8.  
  9. int main() { 
  10.    auto func1 = [](int k) { 
  11.        // std::lock_guard lock(mutex_); 
  12.        std::unique_lock 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中環(huán)境中,必須使用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 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 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 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,用于原子操作,使用這種方式既可以保證線程安全,也不需要使用鎖來進行臨界區(qū)保護,對一些普通變量來說尤其方便,看代碼:

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

多線程

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

 
 
 
  1. #include  
  2. #include  
  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); // d是將亡值 

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

std::function和lambda表達式

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

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

 
 
 
  1. std::function f; // 這里表示function的對象f的參數是int,返回值是void 
  2. #include  
  3. #include  
  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 f_display = print_num; 
  20.    f_display(-9); 
  21.  
  22.    // 存儲 lambda 
  23.    std::function f_display_42 = []() { print_num(42); }; 
  24.    f_display_42(); 
  25.  
  26.    // 存儲到 std::bind 調用的結果 
  27.    std::function f_display_31337 = std::bind(print_num, 31337); 
  28.    f_display_31337(); 
  29.  
  30.    // 存儲到成員函數的調用 
  31.    std::function 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 f_num = &Foo::num_; 
  38.    std::cout << "num_: " << f_num(foo) << '\n'; 
  39.  
  40.    // 存儲到成員函數及對象的調用 
  41.    using std::placeholders::_1; 
  42.    std::function f_add_display2 = std::bind(&Foo::print_add, foo, _1); 
  43.    f_add_display2(2); 
  44.  
  45.    // 存儲到成員函數和對象指針的調用 
  46.    std::function f_add_display3 = std::bind(&Foo::print_add, &foo, _1); 
  47.    f_add_display3(3); 
  48.  
  49.    // 存儲到函數對象的調用 
  50.    std::function 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表達式將這種方便發(fā)揮到了極致,可以在需要的時間就地定義匿名函數,不再需要定義類或者函數等,在自定義STL規(guī)則時候也非常方便,讓代碼更簡潔,更靈活,提高開發(fā)效率。

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中還進一步支持了日期和時區(qū)。這里簡要介紹下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 milliseconds; 
  2. typedef duration seconds; 

duration具體模板如下:

 
 
 
  1. template  > 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  class ratio; 

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

time_point

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

 
 
 
  1. std::chrono::time_point 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

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

system_clock

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

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


網站欄目:聊聊我常用的10個C++新特性
文章網址:
http://www.5511xx.com/article/cojhgde.html