是否有在C ++中进行强有力保证交换的工具

时间:2017-02-07 11:03:34

标签: c++ exception-handling

我一直在寻找一个设施来交换两个具有强大异常保证的物品。那是;让交换完全进行,或者在异常情况下使目标处于初始状态。当前标准中是否有任何内容允许这样做,我找不到任何东西,虽然看起来很容易写。

我在下面的内容是我为了试验我正在寻找的东西而放在一起的版本,但它是noexcept,这不仅仅是我要求的强大"保证。出现了强有力的保证"无法测试,但noexcept保证可以。

#include <iostream>
#include <type_traits>

// Guarantee to exchange l and r fully
// or (not compile) leave them in the initial state
template<typename T>
void strong_exchange(T & l, T &r) noexcept
{
    using std::swap;
    static_assert( noexcept( swap(l, r) ), "Types must be noexcept swappable");
    swap(l, r);
}

struct X
{
    X()
    {
        throw "fish";
    }

    X(X &&) = delete;
};

int main(void)
{
    int a, b;
    strong_exchange(a, b);

    X i, j;
    strong_exchange(i, j);
}

2 个答案:

答案 0 :(得分:1)

可能不可能:

如果复制分配不是noexcept(或执行复制的其他方式),则不可能。如果它是noexceptstd::swap()应该做的事情。否则,可能没有什么可以做的。

答案 1 :(得分:0)

@Incomputable突出了这个问题,但我要提供完整性的答案。

  • 您要分配一个课程,但要确保有一个课程 强烈保证它将完全复制或根本不复制 面对例外......因此出现了唯一可行的解​​决方案 在编译时进行静态断言检查以确保这一点 会发生的。使用std :: move不是保证,因为它可以调用 复制构造函数可能会抛出,也可能无法提供 全部或全部保证。
  • 在我的具体情况下,它是一组必须的配置对象 总是有效的,因为我不能保证没有检查 手动所有对象并希望实现者可以提供 保证,我写了一个noecept_assign函数 应该确保未来的情况。一个完整的例子 如下。
#include <iostream>
#include <type_traits>

// Guarantee to exchange l and r fully or not compile.
template<typename T>
void noexcept_swap(T & l, T &r) noexcept
{
    using std::swap;
    static_assert( noexcept( swap(l, r) ), "Types must be noexcept swappable");
    swap(l, r);
}

// Guarantee to full assign r to l or not compile.
template<typename T>
void noexcept_assign(T & l, T r) noexcept
{
    noexcept_swap(l, r);
}

struct Exchangeable
{
    Exchangeable() { }

    // C++ std::swap requires these two for now thorw, so noexcept_swap will also need them
    Exchangeable(Exchangeable &&) noexcept { }
    Exchangeable & operator=(Exchangeable &&) noexcept { }

    // for noexcept_assign these is also required, since a copy is made durring assignment    Exchangeable(Exchangeable &) noexcept { }
    Exchangeable & operator=(const Exchangeable &) noexcept { }
};

// This class is the same as the above, but it does not have
// a noexcept guarantee on the methods
struct NotExchangeable
{
    NotExchangeable()  {}
    NotExchangeable(NotExchangeable &&) {}
    NotExchangeable & operator=(NotExchangeable &&) { }

    NotExchangeable(const NotExchangeable &) { }
    NotExchangeable & operator=(const NotExchangeable &) { }
};

int main(void)
{
    int a, b;
    noexcept_swap(a, b); // OK
    noexcept_assign(a, b); // OK

    Exchangeable i, j;
    i = j; // Might throw and fail to do a full copy. Depends.
    noexcept_swap(i, j); // OK
    noexcept_assign(i, j); // OK

    NotExchangeable x, y;
#if 0
    noexcept_swap(x, y); // Fails to compile and emits assertion
    noexcept_assign(x, y); // Fails to compile and emits assertion
#endif
}