C++11部分新特性

C++11新特性概述

       C++11標準是C++語言的重大改動。在C++11之前,C++本身更像C語言,兼容和借用了C語言的很多特性。在C++11之後,C++語言更多是借鑑了JAVA、python等所謂現代語言的特點。經過C++11的標準,C++語言長得更像現代語言,但同時,也導致了C++語言的多種特性:既不像C語言本身那麼精煉,又不像真正的純面嚮對象語言。C++11之後的C++語言,功能更加複雜,更加多樣,也造成了C++的編譯器過重(幾乎在所有語言中,C++編譯器是運行最慢的)。

        C++11增加了很多特性,我本人在以前的博客中也有過介紹。今天對這幾個特性進行論述:1)std::stoi; 2)匿名函數;3)右值引用。

1.std::stoi等函數

        std::stoi等函數均是C++11才引入的,一起引入的還有atoll、stoul、stoull、stof、stod、stold和to_string。stoi嚴格來說,最大的特點不是增加了標準庫的字符串轉爲數字,而是引入了異常機制。

        std::stoi的異常規則是:

        1)若不能進行轉換則爲 std::invalid_argument;
        2)若轉換值會落在結果類型的範圍外,或若底層函數( std::strtol 或 std::strtoll )設置 errno 爲 ERANGE 則爲 std::out_of_range 。

        對於標準字符串爲空串,std::stoi將拋出 std::invalid_argument異常。對於超出範圍的數,則拋出std::out_of_range的異常。這和atoi函數是有區別的。atoi對於錯誤的數,會返回0而不拋出異常。

        這個函數,其實隱含着幾個思想:

        1)C++11對異常的支持:在很多C++思想上,是對異常不支持的,認爲異常帶來了冗餘,並無過多優點;但C++11更多的是對異常這一機制的支持。

       2)錯誤處理機制:明確支持範圍,對於不支持的語法,進行暴露而不是屏蔽。

2.匿名函數

       匿名函數是C++11引入的。但嚴格來講,C++很早就有類似匿名函數的思想,比如函數指針,比如仿函數。

       匿名函數的思想是:不提供具體的函數命名,而只提供程序表達式;從邏輯上講,這些程序表達式是一個功能,但不提供具體的名稱;從實體上講,這些部分作爲一個內存塊運行在內存中,而不像傳統的函數一樣,提供了一個地址作爲變量名,通過地址指向運行內存。

       匿名函數又成爲Lamba表達式,語法是:[capture](parameters)->return-type{body},其中參數類型和返回類型可以省略。

        一個簡單的匿名函數的樣例是:

      

[](int x, int y) -> int { int z = x + y; return z; }

       

    匿名函數(Lambda函數)可以引用在它之外聲明的變量。這些變量的集合叫做一個閉包。閉包被定義在Lambda表達式聲明中的方括號[]內. 這個機制允許這些變量被按值或按引用捕獲.下面這些例子就是:     

[]        //未定義變量.試圖在Lambda內使用任何外部變量都是錯誤的.
[x, &y]   //x 按值捕獲, y 按引用捕獲.
[&]       //用到的任何外部變量都隱式按引用捕獲
[=]       //用到的任何外部變量都隱式按值捕獲
[&, x]    //x顯式地按值捕獲. 其它變量按引用捕獲
[=, &z]   //z按引用捕獲. 其它變量按值捕獲

       簡單提供一個匿名函數的例子:

       

#include <vector>
#include <iostream>
#include <algorithm>


int main(int argc, char *argv[])
{
    std::vector<int> vTest;
    int iTotal = 0;

    for(int i = 0; i < 10; i++)
    {
        vTest.push_back(i);
    }

    std::for_each(
        begin(vTest),
        end(vTest),
        [&iTotal](int x)
        {
            iTotal += x;
        }
    );

    std::cout << iTotal  << std::endl;

    return 0;
}

       匿名函數的語義含義是:提供一個程序塊,可以自由實現功能,而不注重這個程序的位置和命名。

       匿名函數的優缺點:

       1)優點:函數(功能)隨時實現和釋放,靈活好用;

       2)缺點:匿名函數一般功能比較單一,並作爲獨立功能支持是缺乏優勢的。

       匿名函數最先體現在Lisp語言中,現在被C++、JAVA、C#、python、Golang廣泛支持。

3.右值引用

       在計算機語言中,左值和右值具有很大不同。左值在尋址過程中是可識別的,而右值在內存識別中是不可識別的。這會造成語法的差異性:        

int x;
x = 4; //支持
4 = x; //不支持 

      傳統上,一直有對左值的引用,但C++11增加了對右值的引用;右值的引用,意味着可以對右值獲得控制權,並對右值進行操作。

       C++11右值的語法如下:

#include <iostream>


void process_value(int& i)
{
    std::cout << "LValue processed: " << i << std::endl;
}

void process_value(int &&i)
{
    std::cout << "RValue processed: " << i << std::endl;
    i += 1;
    std::cout << "RValue processed: " << i << std::endl;
}

int main(int argc, char *argv[])
{
    int a = 0;
    process_value(a);
    process_value(1);

    return 0;
}

      右值引用是用來支持轉移語義的。轉移語義可以將資源 ( 堆,系統對象等 ) 從一個對象轉移到另一個對象,這樣能夠減少不必要的臨時對象的創建、拷貝以及銷燬,能夠大幅度提高 C++ 應用程序的性能。臨時對象的維護 ( 創建和銷燬 ) 對性能有嚴重影響。
       轉移語義是和拷貝語義相對的;拷貝語義意味着資源全部重新生成一遍,而轉移語義只是讓資源的所有權換到了另一個部分。

      理解轉移語義的一個重要參考是淺拷貝。但與淺拷貝不同的是:如果是淺拷貝的話,一個內存對象銷燬,另一個淺拷貝的把內存也會銷燬;但轉移語義由於添加了引用,當一個內存對象銷燬時,內存並不會釋放掉。

這兩段程序上傳到github:

1)https://github.com/diziqian/lambdaTest

2)https://github.com/diziqian/rRefTest

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章