描述
头文件 <boost/throw_exception.hpp>
提供了一个通用的 Boost 基础设施,用于抛出异常,其形式为函数 boost::throw_exception
和宏 BOOST_THROW_EXCEPTION
。
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
支持。
在 catch(std::exception const & x)
之后,可以使用 boost::get_throw_location(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 版本中的更改
-
添加了
throw_exception
的一个重载,它接受一个boost::source_location
对象。
注意
|
在禁用异常的情况下使用 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
的类型的对象,如果E
尚未派生自它,则派生自boost::exception
,并包含对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
的类型的对象,如果E
尚未派生自它,则派生自boost::exception
,并包含对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:版权和许可证
本文档为
-
版权所有 2019, 2022 Peter Dimov
-
根据 Boost 软件许可证,版本 1.0 分发。