Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb SutterAndrei Alexandrescu, C++ Coding Standards

描述

头文件 <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_exceptionBOOST_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”函数 f1f2 如何接受一个源位置参数,该参数默认为 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::exceptionE,则 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 子对象中的源位置(如果有)。

  • 否则,返回默认构造的源位置。

本文档是