查看 std::exception 的定义,除了析构函数,其他包括默认构造和拷贝构造在内的函数都声明为 noexcept:
因为不允许复制
std::exception抛出异常,故当派生类(例如std::runtime_error)必须管理用户定义的诊断信息时,常将它实现为写时复制的字符串。
查看 std::logic_error 的定义 或 std::runtime_error 的定义:
因为不容许复制
std::logic_error抛出异常,通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收std::string&&参数的理由:无论如何它必须复制内容。
为什么
std::exception拷贝构造不允许抛出异常?反证法。如果允许其构造抛出异常,异常又继承自
std::exception,还是直接崩溃更合理。std::logic_error等以字符串为入参的构造函数是可能抛出std::bad_alloc异常的,为什么子类的拷贝构造不能抛出异常?不抛异常是理想状态,能够实现就尽力实现。
domain_error overflow_error 和 underflow_error,并未用于数学函数中
mathematical functions report domamin/overflow/underflow errors as specified in math_errhandling.
标准库里的异常都是按需建立的,大多服务于特定的函数或库。能够在项目中借鉴、使用的也就七八个类型:
logic_error及其大部分子类:invalid_argument,domain_error,length_error,out_of_rangeruntime_error及其部分子类:range_error,overflow_error,underflow_error
相同层级的各异常类型的使用场景并非严格分离的,多个异常的定义存在重复、交叉,在同一场景中往往存在多个异常都可以使用。比如,
- 用于线程库的
future_error从logic_error继承;但 - 用于正则表达式库的
regex_error和用于格式化库的format_error又是从runtime_error继承;而 - 用于
optional、variant和any等类型的 bad_xxx 这些又是直接从std::exception继承 - 在函数
std::stoi抛出out_of_range的场景是不是更符合range_error的定义
又比如:length_error 和 range_error 很像;invalid_argument 和 domain_error 重叠;
C++ When to use which (standard) exception?
异常继承体系最初区分 logic error 和 runtime error 就过于理想,最终还是要 服务于具体的某个函数或库 才有意义。
以下表格 摘自,并修正错误
| 异常 | 描述 |
|---|---|
| std::exception | 该异常是所有标准 C++ 异常的父类。 |
| std::bad_alloc | 该异常可以通过 new 抛出。 |
| std::bad_cast | 该异常可以通过 dynamic_cast 抛出。 |
| std::bad_exception | 这在处理 C++ 程序中无法预期的异常时非常有用。 |
| std::bad_typeid | 该异常可以通过 typeid 抛出。 |
| std::logic_error | 理论上可以通过读取代码来检测到的异常。 |
| std::domain_error | 当使用了一个无效的数学域时,会抛出该异常。 |
| std::invalid_argument | 当使用了无效的参数时,会抛出该异常。 |
| std::length_error | 当创建了太长的 std::string 时,会抛出该异常。 |
| std::out_of_range | 该异常可以通过方法抛出,std::bitset<>::operator[]() |
| std::runtime_error | 理论上不可以通过读取代码来检测到的异常。 |
| std::overflow_error | 当发生数学上溢时,会抛出该异常。 |
| std::range_error | 当尝试存储超出范围的值时,会抛出该异常。 |
| std::underflow_error | 当发生数学下溢时,会抛出该异常。 |
跨线程使用异常
跨线程使用异常,优先使用 std::future,或者请移步 std::exception_ptr 类型。
定义
std::future使用了后者;而后者就是为跨线程捕获异常新增的特性。
logic_error
It reports errors that are a consequence of faulty logic within the program such as violating logical preconditions or class invariants and may be preventable.
No standard library components throw this exception directly
invalid_argument.
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.
domain_error
domain_error, that is, situations where the inputs are outside of the domain on which an operation is defined.
The standard library components do not throw this exception。和 std::invalid_argument 的区别?
length_error
attempt to exceed/超出 implementation defined length limits for some object.
This exception is thrown by member functions of std::basic_string and std::vector::reserve
out_of_range
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 functions (e.g. std::vector::at and std::map::at).
future_error(C++11)
that is thrown on failure by the functions in the thread library.
runtime_error
It reports errors that are due to events beyond the scope of the program and can not be easily predicted.
Exceptions of type std::runtime_error are thrown by the following standard library components: std::locale::locale and std::locale::combine.
range_error
range errors (that is, situations where a result of a computation cannot be represented by the destination type).
The only standard library components that throw this exception are std::wstring_convert::from_bytes and std::wstring_convert::to_bytes.
template class std::wstring_convert is deprecated in c++17.
overflow_error
to report arithmetic 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_ulong and std::bitset::to_ullong.
underflow_error
to report arithmetic 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.
regex_error(C++11)
to report errors in the regular expressions library.
tx_exception(TM TS)
can be used to cancel and roll back an atomic transaction initiated by the keyword atomic_cancel.
nonexistent_local_time(C++20)
to report that an attempt was made to convert a nonexistent std::chrono::local_time to a std::chrono::sys_time without specifying a std::chrono::choose (such as choose::earliest or choose::latest).
This exception is thrown by std::chrono::time_zone::to_sys and functions that call it (such as the constructors of std::chrono::zoned_time that takes a std::chrono::local_time).
Ambiguous and nonexistent local times can occur as a result of time zone transitions (such as daylight saving time/夏令时).
ambiguous_local_time(C++20)
to report that an attempt was made to convert a ambiguous std::chrono::local_time to a std::chrono::sys_time without specifying a std::chrono::choose (such as choose::earliest or choose::latest).
This exception is thrown by std::chrono::time_zone::to_sys and functions that call it (such as the constructors of std::chrono::zoned_time that takes a std::chrono::local_time).
Ambiguous and nonexistent local times can occur as a result of time zone transitions (such as daylight saving time/夏令时).
format_error(C++20)
to report errors in the formatting library.
system_error(C++11)
thrown by various library functions (typically the functions that interface with the OS facilities, e.g. the constructor of std::thread) when the exception has an associated std::error_code, which may be reported.
ios_base::failure(C++11)
is thrown on failure by the functions in the Input/Output library.
filesystem::filesystem_error(C++17)
is thrown on failure by the throwing overloads of the functions in the filesystem library.
1 | std::uintmax_t file_size( const std::filesystem::path& p ); |
bad_optional_access(C++17)
be thrown by std::optional::value when accessing an optional object that does not contain a value.
bad_typeid
is thrown when a typeid operator is applied to a dereferenced null pointer value of a polymorphic type.
多态,含有虚函数的类型。
std::nullptr_t 类型很奇特,它不是指针类型。即 std::nullptr_t p = nullptr; 对变量 *p 解引用是错误的。
bad_cast
is thrown when a dynamic_cast to a reference type fails the run-time check (e.g. because the types are not related by inheritance), and also from std::use_facet if the requested facet does not exist in the locale.
bad_any_cast(C++17)
be thrown by the value-returning forms of std::any_cast on failure.
和类型 std::any 相关
bad_weak_ptr(C++11)
thrown by the constructors of std::shared_ptr that take std::weak_ptr as the argument, when the std::weak_ptr refers to an already deleted object.
优先使用 std::weak_ptr<T>::lock 避免上述异常。
bad_function_call(C++11)
thrown by std::function::operator() if the function wrapper has no target.
bad_alloc
thrown as exceptions by the allocation functions to report failure to allocate storage.
bad_array_new_length(C++11)
thrown as exceptions by the new-expressions to report invalid array lengths.
bad_exception
thrown by the C++ runtime in the following situations:
- If
std::exception_ptrstores a copy of the caught exception and if the copy constructor of the exception object caught bystd::current_exceptionthrows an exception, the captured exception is an instance ofstd::bad_exception.
bad_variant_access(C++17)
thrown in the following situations:
std::get(std::variant)called with an index or type that does not match the currently active alternativestd::visitcalled to visit a variant that is valueless_by_exception