【问题标题】:What if an object passed into std::swap throws an exception during swapping?如果传入 std::swap 的对象在交换期间抛出异常怎么办?
【发布时间】:2013-01-30 10:15:15
【问题描述】:

C++ 标准保证std::swap 不会抛出异常。但是,如果要交换的对象在交换期间抛出异常怎么办?接下来,调用者应该如何发现异常发生了?来电者应该采取什么措施?

PS:构造函数抛出异常是很常见的。

struct A
{
    A(const A&)
    {
        throw 1;
    }

    A& operator =(const A&)
    {
        throw 2;
        return *this;
    }
};

int main()
{
    A a1, a2;
    std::swap(a1, a2); // An exception happened, but the caller doesn't know.
    // How to do here ???
}

【问题讨论】:

  • A 的作者因为没有提供不抛出的 swap(A, A) 过载而被鞭打 10 次
  • @rhalbersma:并不是说提供重载会有所帮助,因为提问者的代码完全限定了调用std::swap
  • @SteveJessop 看到我的回答为什么确实会好很多。
  • "构造函数抛出异常是很常见的。" 复制构造函数抛出异常不是很常见(外部内存分配错误)。

标签: c++ exception c++11 standards swap


【解决方案1】:

C++ 标准保证 std::swap 不会抛出异常。

不,它没有。请参阅 20.2.2 或 the reference。两个 std::swap 重载有两个 noexcept 规范:

template<class T> void swap(T& a, T& b)
noexcept(noexcept(
    std::is_nothrow_move_constructible<T>::value &&
    std::is_nothrow_move_assignable<T>::value
))

template<class T, size_t N>
void swap(T (&a)[N], T (&b)[N])    
noexcept(noexcept(swap(*a, *b)))

当不满足这些条件时,std::swap 可以扔,你可以接住。


在您提供的类的情况下,谓词std::is_nothrow_move_constructiblestd::is_nothrow_move_assignable 为假,因此实例化std::swap&lt;A&gt; 没有不抛出保证。从这个交换中捕获异常是完全合法的。

【讨论】:

  • 这些条件怎么能不满足呢?没有noexcept 规范就没有其他重载。您无法捕获从 std::swap 中抛出的异常
  • swap 有一个条件 noexcept 规范。当使用移动构造和移动分配为noexcept 的类型实例化时,它是noexcept。否则它可以抛出任何东西。
  • @rhalbersma cppreference 有一些很好的描述 the noexpect specifierthe noexpect operator 的工作原理,请阅读
【解决方案2】:

该标准通常不保证交换不会抛出。

从 20.2.2/1 开始:

template void swap(T& a, T& b) noexcept(见下文);

备注:noexcept里面的表达式等价于:

 is_nothrow_move_constructible<T>::value &&
 is_nothrow_move_assignable<T>::value

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    相关资源
    最近更新 更多