第十章 C++11新特性

0
11

目录

  • 统一的初始化方法
  • 成员变量可以赋予默认初始值
  • auto自动类型关键字
  • decltype关键字
  • 基于范围的for循环
  • 智能指针shared_ptr
  • 空指针nullptr
  • 无序容器(哈希表)
  • Lambda表达式
  • 右值引用T&&和move移动语义
  • 正则表达式
  • 强制类型转换
  • 异常处理
  • 运行时类型检查

统一的初始化方法

  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;
    

<

发布回复

请输入评论!
请输入你的名字