欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第十章 C++11新特性

程序员文章站 2022-07-05 11:58:55
[TOC] 统一的初始化方法 1. 通过花括号实现各类变量初始化(允许花括号嵌套) 成员变量可以赋予默认初始值 1. 示例 auto自动类型关键字 1. 定义变量时,通过所赋予的值在编译时自动判断变量类型 2. 可用于模板返回值,提升模板灵活性 decltype关键字 1. 用于获取变量或表达式返回 ......

统一的初始化方法

  1. 通过花括号实现各类变量初始化(允许花括号嵌套)

    int arr[3]{1,2,3};
    vector<int> iv{1,2,3};
    map<int,string> mp{{1,"hello"},{2,"world"}};
    int *p=new int[20]{1,2,3}; //前三个变量初始化为1,2,3,其余用默认构造函数初始化
    struct a{int i,j; a(int m,int n):i(m),j(n){}}
    a func(int m,int n){return {m,n};}
    a* pa=new a{2,3};
    

成员变量可以赋予默认初始值

  1. 示例
    class a{
        public:
        i=5;
    }
    

auto自动类型关键字

  1. 定义变量时,通过所赋予的值在编译时自动判断变量类型

  2. 可用于模板返回值,提升模板灵活性

    template<class t1,class t2>
    auto func(t1 x,t2 y)->decltype(x+y){
        return x+y;
    } //auto可以不为t1、t2中的一种,->decltype(x+y)返回值类型声明也可省略
    

decltype关键字

  1. 用于获取变量或表达式返回值类型

  2. 双括号返回相应类型的引用

    int i;
    decltype(i) x=5;
    decltype((i+x)) y=x;
    

基于范围的for循环

  1. 格式:for(元素类型 i:数组等名)

  2. 获取时元素,而非指针

    int ary[]{1,2,3,4,5};
    for(int &e:ary) e*=2;
    for(int e:ary) cout<<e<<endl; //2,4,6,8,10
    map<int,string> mp{{1,"a"},{2,"b"}};
    for(auto &e:mp) cout<<e.first<<" "<<e.second<<endl; 
    

智能指针shared_ptr

  1. 需要头文件<memory>

  2. 写法:shared_ptr ptr(new t);

  3. 自动托管指针,程序结束或托管数为0时自动释放new动态分配的内存

  4. 多个shared_ptr对象可以同时托管一个指针,系统会维护一个托管计数

  5. 不能用于托管指向动态分配的数组

  6. 创建后的指针用法与一般指针相同

    int *p=new int,*p2=new int{1};
    shared_ptr<int> sp1(p);
    shared_ptr<int> sp2(sp1);
    sp2.reset(); //清空sp2
    sp2.reset(p2); //会置托管计数为1,只能用于智能指针第一次指向p2区域。否则可能出错(delete多次)
    sp2=sp1; p2=sp1.get(); //get函数获取地址
    

空指针nullptr

  1. 与null和0的区别:包含类型,能够转换位bool型,却不能转化为整型

  2. 可以直接和null和nullptr比较

  3. 不同类型的指针不能比较(如double*和int* 型)

    int *p1==null,*p2=nullptr;
    shared_ptr<double> p3=nullptr;
    if(p1==p2) cout<<"equal\n"; //相等
    if(p3==null) cout<<"equal\n"; //相等
    if(p3==nullptr) cout<<"equal\n"; //相等
    bool b=nullptr; //b=false
    int i=nullptr; //错误❌
    

无序容器(哈希表)

  1. unordered_map
  2. 使用与map类似
  3. 插入、查找元素的时间复杂度几乎为常数,但空间占用较多

lambda表达式

  1. [外部变量范围方式说明符](形参表)->返回值类型{ 语句组 }
    "->返回值类型"也可以没有,由编译器自动判断

    外部变量访问符 含义
    [] 不使用任何外部变量
    [=] 以传值方式使用外部变量
    [&] 以引用方式使用外部变量
    [x,&y] 传值方式使用x,引用方式使用y
    [=,&x,&y] 引用方式使用x,y,传值方式使用其他变量
    [&,x,y] 传值方式使用x和y,引用方式使用其他变量
  2. 示例

    cout<<[](double x,double y){return x+y;}(1.1,2.2)<<endl; //3.3
    int x=100,y=200;
    auto ff=[&x,&y](int n){
        x++;y++;
        return n*n;
    }
    cout<<ff(15)<<" "<<x<<" "<<y<<endl; //225 101 201
    function<int(int)> fib=[&fib](int n){return n<=2?1:fib(n-1)+fib(n-2);} 
    //无法由返回值确定返回类型,不能用auto。第一个int代表返回值,第二个int代表函数形参表
    cout<<fib(5)<<endl;
    sort(arr,arr+5,[](int a,int b){return a<b;});
    

右值引用t&&和move移动语义

  1. 详见

  2. c++中所有的值都必然属于左值、右值二者之一。左值是指表达式结束后依然存在的持久化对象,右值是指表达式结束时就不再存在的临时对象。所有的具名变量或者对象都是左值,而右值不具名。很难得到左值和右值的真正定义,但是有一个可以区分左值和右值的便捷方法:看能不能对表达式取地址,如果能,则为左值,否则为右值

  3. 目的:提高程序运行效率,减少需要深拷贝的对象的深拷贝次数(通过直接夺取变量已分配动态分配空间)

  4. 具体类型
    左值引用, 使用 t&, 只能绑定左值

    右值引用, 使用 t&&, 只能绑定右值

    常量左值, 使用 const t&, 既可以绑定左值又可以绑定右值

    已命名的右值引用,编译器会认为是个左值

    编译器有返回值优化,但不要过于依赖

  5. 移动构造函数 和移动赋值函数,如string(string&& str)string& operator= (string&& str)

  6. std::move()用于告诉编译器尽量将该变量当成右值处理,不存在移动拷贝、移动赋值时再考虑普通方式

  7. dev c++中,return局部对象,对导致优化,不调用移动或复制构造函数

  8. 可移动但不可复制的对象:

    struct a{
        a(const a& a)=delete;
        a(const a&& a){cout<<"move constructor."<<endl;}
        a(){}
    }
    

正则表达式

  1. 需包含<regex>头文件

  2. 示例:

    regex reg("\\d{3}{[a-za-z]+}.(\\d{3}|n/a)\\s\\1"); //在c/c++中反斜杠必须写2个以反义
    cout<<regex_match("123hello n/a hello",reg)<<endl; //输出1,匹配成功
    string s("123hello n/a hello");
    cout<<regex_match(s,reg)<<endl; //输出0
    

强制类型转换

  1. static_cast
    • 用于比较“自然”和低风险类型的转换,如整型与字符型、浮点型的转换
    • 不能用于不同类型指针、引用转换,或整型与指针的转换
  2. reinterpret_cast
    • 用于不同类型指针、引用的转换,以及指针和能容纳下指针的整数类型的转换,执行逐个比特拷贝的操作
    • 不进行类型检查
  3. const_cast
    • 用来去除const属性,将const指针、引用转为同类型非const类型引用
  4. dynamic_cast
    • 专门用于将多态基类指针或引用转换成派生类指针、引用。
    • 对于不安全的指针转换(指针不是指向派生类对象),转换结果等于null
    • 对于不安全的引用转换,抛出bad_cast异常

异常处理

  1. try中进行可能异常的操作,将异常传递给catch

  2. throw主动抛出异常

  3. catch捕获try传递的异常,可以存在多个catch函数,从上到下对异常进行类型匹配,catch(...)表示匹配任意类型

  4. 发生异常后,try范围内后续命令不再执行,直到异常被捕获

  5. 如果异常未在函数内部处理,就会被抛给上一级的函数

  6. 常见的异常类(从exception类派生而来,位于<stdexcept>中,类型异常位<typeinfo>

    1. out_of_range 如vector、string用at函数范围越界时
    2. bad_alloc 动态分配内存请求失败(typeinfo头文件中)
    3. bad_cast 用dynamic转换基类引用失败(typeinfo头文件中)

    --> 通过异常对象的what()函数获取异常信息

运行时类型检查

  1. 需要<typeinfo>头文件

  2. 对于多态类,会返回实际指向的对象类型

  3. 示例

    long n;
    cout<<typeid(n).name()<<endl;