描述
头文件 <boost/throw_exception.hpp>
以函数 boost::throw_exception
和宏 BOOST_THROW_EXCEPTION
的形式,提供了通用的 Boost 异常抛出机制。
boost::throw_exception(x);
是 throw x;
的替代品,它在异常处理支持不可用时能够优雅地降级,并将抛出的异常集成到 Boost.Exception 提供的工具中,例如自动提供 boost::exception
类型的基类以及对 boost::exception_ptr
的支持。
当异常处理不可用时,该函数仅声明,而不定义。这允许用户提供自己的定义。
提供了 boost::throw_exception
的一个重载,该重载接受一个 boost::source_location
。它将提供的源代码位置记录到 boost::exception
基类中,之后在捕获异常时可以检索。 boost::diagnostic_information
会自动显示存储的源代码位置。
宏 BOOST_THROW_EXCEPTION(x)
展开为 ::boost::throw_exception(x, BOOST_CURRENT_LOCATION)
,传递当前源代码位置。
当不需要与 Boost.Exception 和 boost::exception_ptr
集成时,可以使用函数 boost::throw_with_location
。它也抛出用户提供的异常,并将其与提供的或推断出的源代码位置关联起来,但它不提供 boost::exception
基类,也不启用 boost::exception_ptr
支持。
通过使用 boost::get_throw_location(x)
,可以在 catch(std::exception const & x)
之后检索由 boost::throw_with_location
抛出的异常的源代码位置。
boost::get_throw_location
也适用于由 boost::throw_exception
的两参数重载或 BOOST_THROW_EXCEPTION
抛出的异常;在这种情况下,它返回存储在 boost::exception
基类中的源代码位置。
示例
使用 BOOST_THROW_EXCEPTION
演示了 BOOST_THROW_EXCEPTION
的用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <boost/throw_exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <stdexcept>
#include <iostream>
void f()
{
BOOST_THROW_EXCEPTION( std::runtime_error( "Unspecified runtime error" ) );
}
int main()
{
try
{
f();
}
catch( std::exception const & x )
{
std::cerr << boost::diagnostic_information( x ) << std::endl;
}
}
示例输出
example.cpp(8): Throw in function void f()
Dynamic exception type: boost::wrapexcept<std::runtime_error>
std::exception::what: Unspecified runtime error
将 boost::throw_exception 与源代码位置一起使用
演示了将 boost::throw_exception
的调用移到一个通用的辅助函数中,该函数可以被标记为 BOOST_NOINLINE
以避免不必要的代码重复。源代码位置显式传递给辅助函数,以便它仍然可以记录逻辑上的抛出点,而不是总是指向辅助函数内部。
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
38
39
40
41
#include <boost/throw_exception.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/core/verbose_terminate_handler.hpp>
#include <stdexcept>
#include <cstddef>
#include <iostream>
BOOST_NORETURN BOOST_NOINLINE
void throw_index_error( std::size_t i, std::size_t n,
boost::source_location const & loc )
{
std::string msg = "Index out of range: "
+ boost::lexical_cast<std::string>( i ) + " >= "
+ boost::lexical_cast<std::string>( n );
boost::throw_exception( std::out_of_range( msg ), loc );
}
void f1( std::size_t i, std::size_t n )
{
if( i >= n )
{
throw_index_error( i, n, BOOST_CURRENT_LOCATION );
}
}
void f2( std::size_t i, std::size_t n )
{
if( i >= n )
{
throw_index_error( i, n, BOOST_CURRENT_LOCATION );
}
}
int main()
{
std::set_terminate( boost::core::verbose_terminate_handler );
f1( 0, 3 );
f2( 4, 3 );
}
示例输出
std::terminate called after throwing an exception:
type: boost::wrapexcept<std::out_of_range>
what(): Index out of range: 4 >= 3
location: <source>:31:34 in function 'f2'
使用 boost::throw_with_location
这个例子演示了 boost::throw_with_location
的一个简单用法。由于未提供源代码位置,因此隐式捕获了对 boost::throw_with_location
的调用的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <boost/throw_exception.hpp>
#include <boost/core/verbose_terminate_handler.hpp>
#include <stdexcept>
int f1( int x )
{
if( x < 0 )
{
boost::throw_with_location(
std::invalid_argument( "f1: x cannot be negative" ) );
}
return x;
}
int main()
{
std::set_terminate( boost::core::verbose_terminate_handler );
return f1( -4 );
}
示例输出
std::terminate called after throwing an exception:
type: boost::detail::with_throw_location<std::invalid_argument>
what(): f1: x cannot be negative
location: <source>:9:9 in function 'f1'
将 boost::throw_with_location 与显式源代码位置一起使用
在这个例子中,对 boost::throw_with_location
的调用被移到了一个通用的辅助函数中。请注意,“API”函数 f1
和 f2
如何接受一个默认值为 BOOST_CURRENT_LOCATION
的源代码位置参数。这使得附加到异常的源代码位置指向对 f2
的调用位置,而不是 f2
内部。
由于像 f2
这样的函数通常在程序的多个地方被调用,所以这通常是我们想要的,因为它使我们能够识别抛出异常的调用点,而不仅仅是知道是 f2
抛出的。
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
38
39
#include <boost/throw_exception.hpp>
#include <boost/core/verbose_terminate_handler.hpp>
#include <stdexcept>
BOOST_NORETURN BOOST_NOINLINE
void throw_invalid_argument( char const * msg,
boost::source_location const & loc )
{
boost::throw_with_location( std::invalid_argument( msg ), loc );
}
int f1( int x,
boost::source_location const & loc = BOOST_CURRENT_LOCATION )
{
if( x < 0 )
{
throw_invalid_argument( "f1: x cannot be negative", loc );
}
return x;
}
int f2( int x,
boost::source_location const & loc = BOOST_CURRENT_LOCATION )
{
if( x < 0 )
{
throw_invalid_argument( "f2: x cannot be negative", loc );
}
return x;
}
int main()
{
std::set_terminate( boost::core::verbose_terminate_handler );
return f1( 3 ) + f2( -11 );
}
示例输出
std::terminate called after throwing an exception:
type: boost::detail::with_throw_location<std::invalid_argument>
what(): f2: x cannot be negative
location: <source>:38:22 in function 'main'
修订历史
1.79.0 版中的更改
-
添加了
boost::throw_with_location
,这是BOOST_THROW_EXCEPTION
对于不使用 Boost.Exception 的程序的更轻量级的替代方案。
1.73.0 版的更改
-
添加了接受
boost::source_location
对象的throw_exception
重载。
注意
|
使用 BOOST_THROW_EXCEPTION 且异常被禁用的项目需要为这个新的重载添加一个定义。 |
参考
<boost/throw_exception.hpp> 纲要
#include <boost/assert/source_location.hpp>
#include <boost/config.hpp>
#include <exception>
namespace boost
{
#if defined( BOOST_NO_EXCEPTIONS )
BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
BOOST_NORETURN void throw_exception( std::exception const & e,
boost::source_location const & loc ); // user defined
#else
template<class E> BOOST_NORETURN void throw_exception( E const & e );
template<class E> BOOST_NORETURN void throw_exception( E const & e,
boost::source_location const & loc );
#endif
} // namespace boost
#define BOOST_THROW_EXCEPTION(x) \
::boost::throw_exception(x, BOOST_CURRENT_LOCATION)
namespace boost
{
template<class E> BOOST_NORETURN void throw_with_location( E && e,
boost::source_location const & loc = BOOST_CURRENT_LOCATION );
template<class E> boost::source_location get_throw_location( E const & e );
} // namespace boost
throw_exception
#if defined( BOOST_NO_EXCEPTIONS )
BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
#else
template<class E> BOOST_NORETURN void throw_exception( E const & e );
#endif
- 要求
-
E
必须有一个公共且无歧义的基类std::exception
。 - 效果
-
-
当异常不可用时,该函数被声明,但未定义。用户需要提供一个合适的定义。
-
否则,如果定义了
BOOST_EXCEPTION_DISABLE
,则函数抛出e
。 -
否则,函数抛出一个派生自
E
的类型的对象,派生自boost::exception
(如果E
尚未派生自它),并包含对boost::exception_ptr
所需的支持。
-
#if defined( BOOST_NO_EXCEPTIONS )
BOOST_NORETURN void throw_exception( std::exception const & e,
boost::source_location const & loc ); // user defined
#else
template<class E> BOOST_NORETURN void throw_exception( E const & e,
boost::source_location const & loc );
#endif
- 要求
-
E
必须有一个公共且无歧义的基类std::exception
。 - 效果
-
-
当异常不可用时,该函数被声明,但未定义。用户需要提供一个合适的定义。
-
否则,如果定义了
BOOST_EXCEPTION_DISABLE
,则函数抛出e
。 -
否则,函数抛出一个派生自
E
的类型的对象,派生自boost::exception
(如果E
尚未派生自它),并包含对boost::exception_ptr
所需的支持。boost::exception
基类被初始化以包含源代码位置loc
。
-
throw_with_location
template<class E> BOOST_NORETURN void throw_with_location( E && e,
boost::source_location const & loc = BOOST_CURRENT_LOCATION );
- 要求
-
std::decay<E>::type
必须有一个公共且无歧义的基类std::exception
。 - 效果
-
-
当异常不可用时,
boost::throw_exception( e, loc );
-
否则,函数抛出一个派生自
E
的类型的对象,使得如果该对象x
被捕获为std::exception
或E
,boost::get_throw_location( x )
会返回loc
。
-
get_throw_location
template<class E> boost::source_location get_throw_location( E const & e );
- 要求
-
E
必须是多态的。 - 效果
-
-
如果
e
是由boost::throw_with_location( x, loc )
抛出的对象的子对象,则返回loc
。 -
如果
dynamic_cast<boost::exception const*>( e )
返回非零值,则返回该boost::exception
子对象中存储的源代码位置(如果存在)。 -
否则,返回默认构造的源代码位置。
-
附录 A:版权和许可
本文档
-
Copyright 2019, 2022 Peter Dimov