Boost C++ 库

...世界上最受尊敬和专家设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

描述

头文件 <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”函数 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 子对象中的源代码位置(如果有)。

  • 否则,返回一个默认构造的源代码位置。

本文档为