Effective C++: noexcept
2019独角兽企业重金招聘Python工程师标准>>>
在正式进入正题之前我们需要了解一点别的知识: 函数签名(function signature).
具体请参阅这里: http://blog.csdn.net/weiwangchao_/article/details/7165467
- 自从C++11起提供了关键字noexcept,用来指明某个函数无法或不打算抛出异常.
另外需要注意的是noexcept(expression)中:
expression的值必须是编译时就得到的(during compling).
例如:
void foo()noexcept;
声明了foo()不打算抛出异常。
但是如果foo()内有异常未被处理,也就是说在我们指定了noexcept的情况下foo()仍然抛出了异常,程序会被终止,然后std::terminal()会调用std::abort().(调用std::abort()也就带来了一个问题,会立刻终止该函数,停止程序,而不做任何清理).
还有需要注意的是noexcept,不会造成stack unwinding(栈展开),也就是说可以表现不抛出异常而不需要额外的开销.
我们再开看一个例子:
像 void foo() noexcept中的noexcept,其实相当于noexcept(true).也就是说我们可以指定一个条件。如果noexcept(false)那么表明有抛出异常的可能。
pair& operator=(pair&& p)noexcept(std::is_nothrow_move_assignable<T1>::value &&std::is_nothrow_move_assginable<T2>::value);
上面的例子中用到了#include<type_traits>中的std::is_nothrow_move_assignable(用来检查针对传入的类型时候存在一个不抛出异常的移动赋值运算符(move-assgin)
demo1(可以编译通过):
#include <iostream>
#include <exception>void func1(const int& number)
{throw std::runtime_error{ "funct1 error!" };
}int main()
{func1(10);return 0;
}
demo2(会产生编译警告,错误的写法实际中不要这么用):
#include <iostream>
#include <exception>void func1(const int& number)noexcept
{throw std::runtime_error{ "funct1 error!" };
}int main()
{func1(10);return 0;
}
demo3(编译通过,但需要特别注意的是,这也是错误的):
#include <iostream>
#include <exception>void func1(const int& number)noexcept //noexcept(true)
{try {throw std::runtime_error{ "funct1 error!" };}catch (const std::runtime_error& error) {std::cerr << error.what() << std::endl;}std::cout << "<---------------------->" << std::endl;
}int main()
{func1(10);return 0;
}
- 从C++17开始noexcept成为了函数类型(function type)的一部分,但它不是函数签名(function signature)的一部分.
demo1:
//尽管异常级别不同,但是由于noexcept只作为function type的一部分,比不能用来overload.
//就像函数返回类型(function return type)一样,也不能用来作为重载的依据.
void f() noexcept;
void f(); // error: different exception specification
demo2:
void ft(); // potentially-throwing
void (*fn)() noexcept = ft; // error
demo3: 针对虚函数
struct B {virtual void f() noexcept;virtual void g();virtual void h() noexcept = delete;
};
struct D: B {void f(); // ill-formed: D::f is potentially-throwing, B::f is non-throwingvoid g() noexcept; // OKvoid h() = delete; // OK
};
- noexcept从C++17开始除了可以指定一个函数不throw异常外(相当于C++11之前的throw()),还提供了限制异常的扩散.具体如何限制呢?
demo1:
#include <iostream>using namespace std;void Throw() { throw 1; }
void NoBlockThrow() { Throw(); }
void BlockThrow() noexcept { Throw(); }//注意指定了noexcept
void BlockThrowNoException()noexcept { throw 1; }int main()
{//case 1: 能够catch到.try {Throw();}catch (...) {cout << "Found throw." << endl; }//case 2: 能够catch到.try {NoBlockThrow();}catch (...) {cout << "Throw is not blocked." << endl; }//case 3: 不能catch到.try {BlockThrow(); }catch (...) {cout << "Found throw 1." << endl;}//case 4: 不能catch到.try {BlockThrowNoException();}catch (...) {cout << "Found throw 1." << endl;}return 0;
}
- 而同样出于安全考虑,自C++11标准中让类的析构函数默认也是noexcept(true)的(无论是我们自己定义的还是default)。当然,如果显式地为析构函数指定了noexcept(false)或者类的基类或成员有noexcept(false)的析构函数,析构函数就不会再保持默认值。
demo1:所有成员函数均为default
输出均为: true
#include <iostream>class Test1
{
public://Test1() {}//Test1(const Test1&) noexcept(false)/*= default;*/ {}//Test1(Test1&&) noexcept(false) {}//Test1& operator=(const Test1&) = default;//Test1& operator=(Test1&&) = default;//~Test1() = default;
};int main()
{Test1 test1;std::cout << std::boolalpha;//输出均为: true;std::cout << noexcept(Test1{}) << std::endl<< noexcept(std::declval<Test1>().~Test1()) << std::endl<< noexcept(Test1{ std::declval<Test1>() }) << std::endl<< noexcept(Test1{ test1 }) << std::endl<< noexcept(Test1{}.operator=(test1)) << std::endl<< noexcept(Test1{}.operator=(std::declval<Test1>())) << std::endl;return 0;
}
demo2: 自定义析构函数(destroy)
产生编译警告,且无法catch到exception.
#include <iostream>class Test1
{
public:~Test1(){throw 1;}
};int main()
{try {Test1 test;}catch (...){std::cout << "Catched the exception!" << std::endl;}return 0;
}
demo3: 自定义构造函数(constructor),但是需要注意的是copy/move-constructor, copy/move-operator=都是default的!
#include <iostream>class Test1
{
public:Test1() {}//Test1(const Test1&) noexcept(false)/*= default;*/ {}//Test1(Test1&&) noexcept(false) {}//Test1& operator=(const Test1&) = default;//Test1& operator=(Test1&&) = default;//~Test1() = default;
};int main()
{Test1 test1;std::cout << std::boolalpha;std::cout << noexcept(Test1{}) << std::endl //false<< noexcept(Test1{ std::declval<Test1>() }) << std::endl<< noexcept(Test1{ test1 }) << std::endl<< noexcept(Test1{}.operator=(std::declval<Test1>())) << std::endl //false<< noexcept(Test1{}.operator=(test1)) << std::endl //false<< noexcept(std::declval<Test1>().~Test1()) << std::endl;return 0;
}
demo4:成员的析构函数potentially-throw
#include <iostream>struct Test
{~Test()noexcept(false) {}
};class Test1
{
private:Test t;public://Test1() {}//Test1(const Test1&) noexcept(false)/*= default;*/ {}//Test1(Test1&&) noexcept(false) {}//Test1& operator=(const Test1&) = default;//Test1& operator=(Test1&&) = default;~Test1() = default;
};int main()
{Test1 test1;std::cout << std::boolalpha;std::cout << noexcept(Test1{}) << std::endl //false<< noexcept(Test1{ std::declval<Test1>() }) << std::endl<< noexcept(Test1{ test1 }) << std::endl<< noexcept(Test1{}.operator=(std::declval<Test1>())) << std::endl //false<< noexcept(Test1{}.operator=(test1)) << std::endl //false<< noexcept(std::declval<Test1>().~Test1()) << std::endl; //falsereturn 0;
}
- template with noexcept operator
函数模板(function template)在声明(declare)中如果带有noexcept operator,在声明这个函数的时候是不会实例化(instantiate)异常级别的(当然可以通过特例化来完成强行异常指定),只有在需要(in needed)的时候才会.
demo 1:
#include <iostream>struct A{
};struct B{int x;
};template<typename T>
void func()noexcept(sizeof(T) >= 4)
{std::cout << "test" << std::endl;
}typedef void (*forA)()noexcept(false);
typedef void (*forB)()noexcept(true);int main()
{forA a = func<A>;forB b = func<B>;return 0;
}
转载于:https://my.oschina.net/SHIHUAMarryMe/blog/683754
Effective C++: noexcept相关推荐
- Item 14: 如果函数不会抛出异常就把它们声明为noexcept
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 在C++98中,异常规范(exception specificat ...
- 【C++学习】Effective C++
本文为Effective C++的学习笔记,第一遍学习有很多不理解的地方,后续需要复习. 0 导读 术语 声明(declaration) 告诉编译器某个东西的名称和类型,但略去细节: 每个函数的声明揭 ...
- 《Effective Modern C++》笔记
文章目录 绪论 第1章 型别推导 条款1:理解模板类型推导 情况1:ParamType 是个指针或引用,但不是万能引用 情况2:ParamType是万能引用 情况3:ParamType既非指针也非引用 ...
- [读书笔记]《Effective Modern C++》—— 移步现代 C++
文章目录 前言 item7:区别使用 () 和 {} 创建对象 item8:优先考虑使用 nullptr 而不是 0 或者 NULL item9:优先考虑别名声明而非 typedefs item10: ...
- 《Effective C++》 笔记
文章目录 0.导读 命名习惯 1.让自己习惯C++ 条款01 条款02:尽量以const.enum.inline替换 #define 条款03:尽可能使用const 1.const与函数声明式关联 2 ...
- Effective Modern C++ 纯人工翻译,持续更新,不为博你眼球,旨在自我提升
文章目录 Effective.Modern.C++ 关键词翻译 Argument Parameter ParamType expr .expression type deduction trailin ...
- Effective C++ 50条款
Effective C++ 50条款 条款 1:尽量用 const 和 inline 而不用#define--尽量用编译器而不用预处理 #define max(a,b) ((a) > (b) ? ...
- [.NET] 《Effective C#》快速笔记 - C# 中的动态编程
<Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...
- Effective STL 50条有效使用STL的经验笔记
Scott Meyers大师Effective三部曲:Effective C++.More Effective C++.Effective STL,这三本书出版已很多年,后来又出版了Effective ...
最新文章
- 阿里p7程序员哀叹:35岁,被通知合同不再续签,输出社会,怎么办?
- 福利 | NVIDIA英伟达免费直播课:带你选择、搭建AI服务器!
- python可以播放音乐吗_详解python播放音频的三种方法
- 链接器ld程序的脚本文件u-boot.lds(二)
- 在 Java CAPS 中使用 LDAP
- Android之提示错误Can not perform this action after onSaveInstanceState
- 肉体之爱的解释圣经_可以解释的AI简介,以及我们为什么需要它
- 6个很棒的PostCSS插件,让您成为一个CSS向导
- springmvc请求返回一个字符_Spring MVC框架详解01
- SLAM_轨迹算法精度评价指标(ATE、RPE)
- 《The Pragmatic Programer》 reading notes
- Windows下usb接口驱动技术(一)
- MysQL索引与事务
- PS技巧一-----镜头光晕
- 【解决方案】Gitlab阿里企业邮箱配置
- leetcode378. 有序矩阵中第K小的元素(Python3)
- 交叉编译工具链使用提示No such file or directory
- 连载 大学生求职七大昏招(七)说谎 6
- 乔布斯在斯坦福大学的演讲--摘录
- android 调用activity方法,Android用代码方式调用其他应用Activity报错