C++学习笔记(14)

二、栈解旋

异常被抛出后,从进入 try 语句块开始,到异常被抛出之前,这期间在栈上构造的所有对象,都会被

自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋。

也就是在执行 throw 前,在 try 执行期间构造的所有对象被自动析构后,才会进入 catch 匹配。

在堆上构造的对象肿么办?

三、异常规范

C++98 标准提出了异常规范,目的是为了让使用者知道函数可能会引发哪些异常。

void func1() throw(A, B, C); // 表示该函数可能会抛出 A、B、C 类型的异常。

void func2() throw(); // 表示该函数不会抛出异常。

void func3(); // 该函数不符合 C++98 的异常规范。

C++11 标准弃用了异常规范,使用新增的关键字 noexcept 指出函数不会引发异常。

void func4() noexcept; // 该函数不会抛出异常。

在实际开发中,大部分程序员懒得在函数后面加 noexcept,弃用异常已是共识,没必要多此一举。

关键字 noexcept 也可以用作运算符,判断表达试(操作数)是否可能引发异常;如果表达式可能引

发异常,则返回 false,否则返回 true。 四、C++标准库异常

五、重点关注的异常

1)std::bad_alloc

如果内存不足,调用 new 会产生异常,导致程序中止;如果在 new 关键字后面加(std::nothrow)选

项,则返回 nullptr,不会产生异常。

示例:

#include <iostream>

using namespace std;

int main()

{

try {

// 如果分配内存失败,会抛出异常。

//double* ptr = new double[100000000000];

// 如果分配内存失败,将返回 nullptr,会抛出异常。

double* ptr = new (std::nothrow) double[100000000000];

if (ptr == nullptr) cout << "ptr is null.\n";

}

catch (bad_alloc& e)

{

cout << "catch bad_alloc.\n";

}

}

2)std::bad_cast

dynamic_cast 可以用于引用,但是,C++没有与空指针对应的引用值,如果转换请求不正确,会出

现 std::bad_cast 异常。

3)std::bad_typeid

假设有表达式 typeid(*ptr),当 ptr 是空指针时,如果 ptr 是多态的类型,将引发 std::bad_typeid

异常。 六、逻辑错误异常

程序的逻辑错误产生的异常 std::logic_error,通过合理的编程可以避免。

1)std::out_of_range

Defines a type of object to be thrown as exception. It reports errors that are consequ

ence of attempt to access elements out of defined range. It may be thrown by the member functions of std::bitset and std::basic_string, by std::

stoi and std::stod families of functions, and by the bounds-checked member access functi

ons (e.g. std::vector::at and std::map::at). 2)std::length_error

Defines a type of object to be thrown as exception. It reports errors that result from

attempts to exceed implementation defined length limits for some object. This exception is thrown by member functions of std::basic_string and std::vector::rese

rve.3)std::domain_error

Defines a type of object to be thrown as exception. It may be used by the implemen

tation to report domain errors, that is, situations where the inputs are outside of the do

main on which an operation is defined. The standard library components do not throw this exception (mathematical functions

report domain errors as specified in math_errhandling). Third-party libraries, however, use

this. For example, boost.math throws std::domain_error if boost::math::policies::throw_on_err

or is enabled (the default setting). 4)std::invalid_argument

Defines a type of object to be thrown as exception. It reports errors that arise becaus

e an argument value has not been accepted. This exception is thrown by std::bitset::bitset, and the std::stoi and std::stof families of

functions. 示例 1:

#include <iostream>

#include <vector>

using namespace std;

int main()

{

try{

vector<int> vv = { 1,2,3 }; // 容器 vv 中只有三个元素。

vv.at(3) = 5; // 将引发 out_of_range 异常。

}

catch (out_of_range) {

cout << "出现了 out_of_range 异常。\n";

}

}

示例 2:

#include <stdexcept>

#include <iostream>

#include <string>

using namespace std;

int main()

{

string str = "123"; // 不会抛出异常。

//string str = ""; // 将抛出 Invalid_argument 异常。

//string str = "253647586946334221002101"; // 将抛出 out_of_range 异常。

try {

int x = stoi(str); // 把 string 字符串转换为整数。

cout << "x=" << x << endl;

}

catch (invalid_argument&) {

cout << " invalid_argument. \n";

}

catch (out_of_range&) {

cout << " out of range. \n";

}

catch (...) {

cout << " something else..." << endl;

}

}

七、其它异常

1)std::range_error

Defines a type of object to be thrown as exception. It can be used to report range e

rrors (that is, situations where a result of a computation cannot be represented by the d

estination type). The only standard library components that throw this exception are std::wstring_conv

ert::from_bytes and std::wstring_convert::to_bytes. The mathematical functions in the standard library components do not throw this exc

eption (mathematical functions report range errors as specified in math_errhandling). 2)std::overflow_error

Defines a type of object to be thrown as exception. It can be used to report arithmet

ic overflow errors (that is, situations where a result of a computation is too large for the

destination type)

The only standard library components that throw this exception are std::bitset::to_ulo

ng and std::bitset::to_ullong. The mathematical functions of the standard library components do not throw this exc

eption (mathematical functions report overflow errors as specified in math_errhandling). Th

ird-party libraries, however, use this. For example, boost.math throws std::overflow_error if b

oost::math::policies::throw_on_error is enabled (the default setting). 3)std::underflow_error

Defines a type of object to be thrown as exception. It may be used to report arithme

tic underflow errors (that is, situations where the result of a computation is a subnormal

floating-point value)

The standard library components do not throw this exception (mathematical functions

report underflow errors as specified in math_errhandling). Third-party libraries, however, u

se this. For example, boost.math throws std::underflow_error if boost::math::policies::throw_o

n_error is enabled (the default setting

4)ios_base::failure

这个异常,程序员不主动找它就没事。

示例:

#include <iostream>

#include <fstream>

int main()

{

using namespace std;

fstream file;

file.exceptions(ios::failbit); // 设置如果出现 ios::failbit,就引发异常。

try

{

file.open("rm.txt", ios_base::in); // 如果打开的文件不存在,就会引发异常。

}

catch (ios_base::failure f)

{

cout << caught an exception: " << f.what() << endl;

}

}

5)std::bad_exception

This is a special type of exception specifically designed to be listed in the dynamic-ex

ception-specifier of a function (i.e., in its throw specifier).

If a function with bad_exception listed in its dynamic-exception-specifier throws an exce

ption not listed in it and unexpected rethrows it (or throws any other exception also not i

n the dynamic-exception-specifier), a bad_exception is automatically thrown. 210、C++断言

一、断言

断言(assertion)是一种常用的编程手段,用于排除程序中不应该出现的逻辑错误。

使用断言需要包含头文件<cassert>或<assert.h>,头文件中提供了带参数的宏 assert,用于程序在

运行时进行断言。

语法:assert(表达式);

断言就是判断(表达式)的值,如果为 0(false),程序将调用 abort()函数中止,如果为非 0(true),

程序继续执行。

断言可以提高程序的可读性,帮助程序员定位违反了某些前提条件的错误。

注意:

 断言用于处理程序中不应该发生的错误,而非逻辑上可能会发生的错误。

 不要把需要执行的代码放到断言的表达式中。

 断言的代码一般放在函数/成员函数的第一行,表达式多为函数的形参。

示例:

#include <iostream>

#include <cassert> // 断言 assert 宏需要包含的头文件。

using namespace std;

void copydata(void *ptr1,void *ptr2) // 把 ptr2 中的数据复制到 ptr1 中。

{

assert(ptr1&&ptr2); // 断言 ptr1 和 ptr2 都不会为空。

cout << "继续执行复制数据的代码......\n";

}

int main()

{

int ii=0,jj=0;

copydata(&ii, &jj); // 把 ptr2 中的数据复制到 ptr1 中。

}

相关推荐
唐诺5 小时前
几种广泛使用的 C++ 编译器
c++·编译器
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__5 小时前
Web APIs学习 (操作DOM BOM)
学习
冷眼看人间恩怨6 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客6 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin6 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos7 小时前
c++---------数据类型
java·jvm·c++
数据的世界018 小时前
.NET开发人员学习书籍推荐
学习·.net
四口鲸鱼爱吃盐8 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
十年一梦实验室8 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵