• noexcept 修饰符


      1.当 noexcept 是标识符时, 它的作用是在函数后面声明一个函数是否会抛出异常.
      2.当 noexcept 是函数时, 它的作用是检查一个函数是否会抛出异常.

    noexcept 标识符

      noexcept 编译期完成声明和检查工作.
      noexcept 主要是解决的问题是减少运行时开销. 运行时开销指的是, 编译器需要为代码生成一些额外的代码用来包裹原始代码,当出现异常时可以抛出一些相关的堆栈stack unwinding错误信息, 这里面包含,错误位置, 错误原因, 调用顺序和层级路径等信息.
      当使用noexcept声明一个函数不会抛出异常候, 编译器就不会去生成这些额外的代码, 直接的减小的生成文件的大小, 间接的优化了程序运行效率.

      noexcept 标识符有几种写法: noexceptnoexcept(true)noexcept(false)noexcept(expression)throw() .
      其中 noexcept 默认表示 noexcept(true).
      当 noexcepttrue 时表示函数不会抛出异常,
      当 noexceptfalse 时表示函数可能会抛出异常.
      throw()表示函数可能会抛出异常, 不建议使用该写法, 应该使用 noexcept(false), c++11 已经使用noexcept, C++20 放弃这种写法.

    // noexcept 标识符
    // noexcept 相当于 noexcept(true)
    // 声明noexcept(true)之后, 将表示这个是不会报错的.
    // 如果报错的话, 进程直接结束, 不会抛出异常信息.
    void example() noexcept {
        cout << "hello called" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    noexcept 函数

      noexcept 函数用来检查一个函数是否声明了 noexcept, 如果声明了noexcept(true)则返回true, 如果声明了noexcept(false)则返回false.

    #include 
    using std::cout;
    using std::endl;
    using std::boolalpha;
    
    // noexcept 标识符
    void foo() noexcept(true) {
        throw 4;
    }
    
    // noexcept 标识符
    void bar() noexcept(false) {
        throw 4;
    }
    
    
    int main(void) {
        // noexcept 函数
        cout << boolalpha << noexcept(foo()) << endl;  // true
        cout << boolalpha << noexcept(bar()) << endl;  // false
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

      noexcept 函数 还可以在常规函数中配合 noexcept(expression) 标识符 共同完成对其他函数是否声明了 noexcept 的检查.

    #include 
    using std::cout;
    using std::endl;
    using std::boolalpha;
    
    
    struct foo {
        int a;
        void getFoo() noexcept(true) {
            cout << "foo.getFoo called" << endl;
        }
        void getBar() noexcept(false) {
            cout << "foo.getBar called" << endl;
        }
    };
    
    
    template
    void example_true(T t) noexcept(noexcept(t.getFoo())) {
        cout << "example called" << endl;
    }
    
    
    template
    void example_false(T t) noexcept(noexcept(t.getBar())) {
        cout << "example called" << endl;
    }
    
    
    int main(void) {
        foo x{};
        cout << boolalpha << noexcept(example_true(x)) << endl;    // true
        cout << boolalpha << noexcept(example_false(x)) << endl;   // false
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    有条件的noexcecpt

      单独使用noexcept,表示其所限定的swap函数绝对不发生异常。然而,使用方式可以更加灵活,表明在一定条件下不发生异常。

        void swap(Type& x, Type& y) noexcept(noexcept(x.swap(y)))    //C++11
        {
            x.swap(y);
        }
    
    • 1
    • 2
    • 3
    • 4

      它表示,如果操作x.swap(y)不发生异常,那么函数swap(Type& x, Type& y)一定不发生异常。
      一个更好的示例是std::pair中的移动分配函数(move assignment),它表明,如果类型T1和T2的移动分配(move assign)过程中不发生异常,那么该移动构造函数就不会发生异常。

        pair& operator=(pair&& __p)
        noexcept(__and_,
                        is_nothrow_move_assignable<_T2>>::value)
        {
            first = std::forward(__p.first);
            second = std::forward(__p.second);
            return *this;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    什么时候该使用noexcept?

      使用noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。然而,并不是加上noexcept就能提高效率,步子迈大了也容易扯着蛋。
      以下情形鼓励使用noexcept:

    • 移动构造函数(move constructor)

    • 移动分配函数(move assignment)

    • 析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。下面代码可以检测编译器是否给析构函数加上关键字noexcept。

        struct X
        {
            ~X() { };
        };
        
        int main()
        {
            X x;
        
            // This will not fire even in GCC 4.7.2 if the destructor is
            // explicitly marked as noexcept(true)
            static_assert(noexcept(x.~X()), "Ouch!");
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 叶子函数(Leaf Function)。叶子函数是指在函数内部不分配栈空间,也不调用其它函数,也不存储非易失性寄存器,也不处理异常。

      最后强调一句,在不是以上情况或者没把握的情况下,不要轻易使用noexception。

  • 相关阅读:
    spring组件之BeanFactory
    腾讯云轻量应用服务器配置表汇总2核2G/2核4G/4核8G/8核16G!
    数据结构之七大排序
    手机定屏死机问题操作指南
    Spire.Office for NET 全家桶最新版7.7.6
    Uni-app 之uParse 富文本解析 完美解析富文本!
    【泛函分析】距离空间的完备性
    网络编程之Socket套接字
    PBI 访问情况
    raise EOFError(“No data left in file“) EOFError: No data left in file
  • 原文地址:https://blog.csdn.net/yaoyaohyl/article/details/127423150