• C++11新特性


    nullptr

    nullptr比NULL更安全。当需要使用NULL时,应使用nullptr代替。

    auto

    自动推断变量类型,常用于迭代器。

    decltype

    自动推断表达式类型。decltype(表达式)

    int x = 1;
    int y = 2;
    decltype(x+y) z;
    

    拖尾返回类型

    用于模板类的后置返回类型。

    template<typename T, typename U>
    auto add(T x, U y) -> decltype(x+y) 
    {
        return x+y;
    }
    

    从 C++14 开始是可以直接让普通函数具备返回值推导,因此下面的写法变得合法:

    template<typename T, typename U>
    auto add(T x, U y)
     {
        return x+y;
    }
    

    for增强

    基于范围的for循环,多用于遍历容器。for(int a:vector){}
    迭代器时是指针,非迭代器时是基本类型。
    因此,迭代器++是地址(指针)++,基本类型++是数值++。
    在顺序取值时使用基本类型,需要特殊位置取值时使用迭代器。

    #include <iostream>
    #include <vector>
    
    int main() {
       std::vector<int> arr(5, 100);
       std::cout << "Start:" << std::endl;
    
       std::cout << "--------值传递(只读)-----------" << std::endl;
       for (auto i : arr) {
          std::cout << i << std::endl;
       }
    
       std::cout << "--------引用(读写)-----------" << std::endl;
       for (auto &i : arr) {
          std::cout << i << std::endl;
          i++;
       }
       for (auto i : arr) {
          std::cout << i << std::endl;
       }
    
       std::cout << "--------const&-----------" << std::endl;
       for (auto i = arr.begin(); i != arr.end(); i++)
       {
          std::cout << *i << std::endl;
       }
    
       std::cout << "--------迭代器-----------" << std::endl;
       for (auto i = arr.begin(); i != arr.end(); i++)
       {
          std::cout << *i << std::endl;
       }
    
       system("pause");
       return 0;
    }
    
    Start:
    --------非引用(只读)-----------
    100
    100
    100
    100
    100
    --------引用(读写)-----------
    100
    100
    100
    100
    100
    101
    101
    101
    101
    101
    --------const&-----------
    101
    101
    101
    101
    101 
    --------迭代器-----------
    101
    101
    101
    101
    101
    Press any key to continue . . .
    

    参数迭代

    #include <iostream>
    #include<cmath>
    #include<vector>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::vector;
    typedef vector<vector<int>> nature;
    
    int main()
    {
       vector<int> singular{ 1,3,5 };
       vector<int> even{ 2,4,6 };
    
       nature number{ singular,even };
    
       for (auto num : number)
       {
          for (auto i : num)
          {
             cout << i << endl;
          }
    
       }
       system("pause");
       return 0;
    }
    
    1
    3
    5
    2
    4
    6
    

    列表初始化

    C++11允许所有类型使用列表初始化方式,{}
    同时也支持自定义类型的列表初始化方式:(待补充)

    #include <initializer_list>
    
    class Magic {
    public:
        Magic(std::initializer_list<int> list) {}
    };
    
    Magic magic = {1,2,3,4,5};
    std::vector<int> v = {1, 2, 3, 4};
    

    模板增强

    外部模板

    template class std::vector<bool>;            // 强行实例化
    extern template class std::vector<double>;  // 不在该编译文件中实例化模板
    

    尖括号 “>”

    在传统 C++ 的编译器中,>>一律被当做右移运算符来进行处理。但实际上我们很容易就写出了嵌套模板的代码:

    std::vector<std::vector<int>> wow;
    

    这在传统C++编译器下是不能够被编译的,而 C++11 开始,连续的右尖括号将变得合法,并且能够顺利通过编译。

    类型别名模板

    在传统 C++中,typedef 可以为类型定义一个新的名称,但是却没有办法为模板定义一个新的名称。因为,模板不是类型。
    C++11 使用 using 引入了下面这种形式的写法,并且同时支持对传统 typedef 相同的功能:

    template <typename T>
    using NewType = SuckType<int, T, 1>;    // 合法
    

    构造函数

    委托构造

    C++11 引入了委托构造的概念,这使得构造函数可以在同一个类中一个构造函数调用另一个构造函数,从而达到简化代码的目的:

    class Base {
    public:
        int value1;
        int value2;
        Base() {
            value1 = 1;
        }
        Base(int value) : Base() {  // 委托 Base() 构造函数
            value2 = 2;
        }
    };
    

    继承构造

    使用using可以直接完成基类的“透传”构造函数。
    多重继承有一定的限制,暂不考虑。
    如果一个继承构造函数不被相关的代码使用,编译器不会为之产生真正的函数代码,这样比透传基类各种构造函数更加节省目标代码空间。

    struct A
    {
      A(int i) {}
      A(double d,int i){}
      A(float f,int i,const char* c){}
    };
    struct B:A
    {
      using A::A;
      //关于基类各构造函数的继承一句话搞定
      //to do something......
    };
    

    Lambda表达式

    Lambda 表达式,实际上就是提供了一个类似匿名函数的特性,而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。
    同时,当某个函数只能传递一个参数,实际中却需要传入两个参数来解决时可以运用Lambda表达式。
    Lambda 表达式的基本语法如下:

    [ caputrue ] ( params ) opt -> ret { body; };
    
    1. []不捕获任何变量。
    2. [&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
    3. [=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。注意值捕获的前提是变量可以拷贝,且被捕获的变量在 lambda 表达式被创建时拷贝,而非调用时才拷贝。如果希望lambda表达式在调用时能即时访问外部变量,我们应当使用引用方式捕获。
    4. [=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。
    5. [bar]按值捕获bar变量,同时不捕获其他变量。
    6. [this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。

    通常情况下,[]都是空:

    stable_sort(words.begin(),words.end(),[](const string &a,const string &b){return a.size()<b.size();});
    

    新增容器

    10.1 std::array

    array是数组的替代品,除了可以随机访问元素,还具有一些迭代器功能。

    std::array<int, 4> arr= {1,2,3,4};
    

    以下行为不可:

    int len = 4;
    std::array<int, len> arr = {1,2,3,4}; // 非法, 数组大小参数必须是常量表达式
    

    10.2 std::list

    std::list是单向列表,当不需要双向迭代时,具有比 std::list 更高的空间利用率。

    10.3 无序容器

    C++11 引入了两组无序容器:
    std::unordered_map/std::unordered_multimap 和 std::unordered_set/std::unordered_multiset。
    TODO:)
    参考:
    www.purethought.cn/2019/09/25/%E7%BC%96%E7%A8%8B/C/%E5%85%B3%E8%81%94%E5%AE%B9%E5%99%A8%E6%80%BB%E7%BB%93/

    10.4 std::tuple元组

    TODO:)

    正则表达式

    TODO:)

    语言级线程支持

    std::thread
    std::mutex/std::unique_lock
    std::future/std::packaged_task
    std::condition_variable

    右值引用和移动语义

    TODO:)

    std::function和std::bind

    std::function

    function的作用是格式化函数,将所有被调用函数统一格式化一种形式,这样做的目的是实现面向接口编程,格式化后的函数形式可以作为接口使用,这在模板中比较常用,如消息总线.
    std::function包含于头文件 #include<functional>中,可将各种可调用实体进行封装统一,包括:

    • 普通函数
    • lambda表达式
    • 函数指针
    • 仿函数(functor 重载括号运算符实现)
    • 类成员函数
    • 静态成员函数

    下面实例通过上述几种方式实现一个简单的比较两个数的大小的功能:

    #include <iostream>
    #include <functional>
     
    using namespace std;
     
    std::function<bool(int, int)> fun;
    

    1.普通函数

    //普通函数
    bool compare_com(int a, int b)
    {
        return a > b;
    }
    

    2.lambda表达式

    //lambda表达式
    auto compare_lambda = [](int a, int b){ return a > b;};
    

    3.仿函数

    //仿函数
    class compare_class
    {
    public:
        bool operator()(int a, int b)
        {
            return a > b;
        }   
    };
    

    4.类成员函数(动态、静态)

    //类成员函数
    class compare
    {
    public:
        bool compare_member(int a, int b)
        {
            return a > b;
        }
        static bool compare_static_member(int a, int b)
        {
            return a > b;
        }
    };
    

    对应的main函数如下:

    int main()
    {
        bool result;
        fun = compare_com;
        result = fun(10, 1);
        cout << "普通函数输出, result is " << result << endl;
        
        fun = compare_lambda;
        result = fun(10, 1);
        cout << "lambda表达式输出, result is " << result << endl;
        
        fun = compare_class();
        result = fun(10, 1);
        cout << "仿函数输出, result is " << result << endl;
        
        fun = compare::compare_static_member;
        result = fun(10, 1);
        cout << "类静态成员函数输出, result is " << result << endl;
        
        //类普通成员函数比较特殊,需要使用bind函数,并且需要实例化对象,成员函数要加取地址符
        compare temp;
        fun = std::bind(&compare::compare_member, temp, std::placeholders::_1, std::placeholders::_2);
        result = fun(10, 1);
        cout << "类普通成员函数输出, result is " << result << endl;
    

    std::bind

    std::bind函数将可调用对象(开头所述6类)和可调用对象的参数进行绑定,返回新的可调用对象(std::function类型,参数列表可能改变),返回的新的std::function可调用对象的参数列表根据bind函数实参中std::placeholders::_x从小到大对应的参数确定。下面以仿函数绑定为例,实现功能:比较输入数是否小于3:

    //bind函数
        std::function<bool(int)> fun2;
        //返回新的可调用对象参数列表只有一个int,std::placeholders::_1表示compare_class()第一个参数
        fun2 = std::bind(compare_class(), 3, std::placeholders::_1);
        result = fun2(3);
        cout << "bind函数测试, result is " << result << endl;
        return 0;
    }
    

    这里重新写一个实例详细说明返回的新的std::function可调用对象的参数列表如何确定:

    #include <iostream>
    #include <functional>
     
    using namespace std;
     
    std::function<int(void)> func;
     
    int testFunc()
    {
    	cout << "global Func" << endl;
    	return 0;
    }
     
    auto lambda = [](void) -> int {cout << "lambda func" << endl; return 0; };
     
    class Func
    {
     
    	int operator()(void)
    	{
    		cout << "仿函数" << endl;
    		return 0;
    	}
    };
     
     
    class CFuntion
    {
    public:
    	int ClassMember(){ cout << "class member function" << endl; return 0; }
    	int static StaticClassFunc(){ cout << "static class member function" << endl; return 0; }
    };
    int main()
    {
    	func = testFunc;
    	func();
     
    	func = lambda;
    	func();
     
    	func = CFuntion::StaticClassFunc;
    	func();
     
    	CFuntion classFunc;
    	func = std::bind(&CFuntion::ClassMember, classFunc);
    	func();
     
    	return 0;
    }
    

    参考链接:
    https://blog.csdn.net/jiange_zh/article/details/79356417
    https://blog.csdn.net/y396397735/article/details/79615834
    https://blog.csdn.net/xiaoyink/article/details/79348806
    https://blog.csdn.net/hailong0715/article/details/54890403

  • 相关阅读:
    分布式系统基础设施
    6种负载均衡算法
    缓存类
    HTTP状态码100、200、300、400、500、600的含义
    Java中的多线程你只要看这一篇就够了(引用)
    An incompatible version 1.1.1 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.17
    EL表达式与JSTL(C)标签
    JSP标准标签库
    SpringMVC HttpMessageConverter 匹配规则
    springboot学习(三)——使用HttpMessageConverter进行http序列化和反序列化
  • 原文地址:https://www.cnblogs.com/chendeqiang/p/12861568.html
Copyright © 2020-2023  润新知