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

猜你喜欢

转载自blog.csdn.net/wangzhezhilu001/article/details/106521655