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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 配置tomcat容器的access.lo
- 下一篇: C#-DataTable分页代码