Is there facility for a strong guaranteed exchange in C++

旧时模样 提交于 2019-12-08 08:17:04

问题


I have been looking for a facility to exchange two items with a strong exception guarantee. That is; to have the exchange proceed totally, or leave the target in the initial state in the face of exceptions. Is there anything included in the current standard that allows this, I have not been able to find anything, although it appears easy to write.

What I have below is a version I put together to try out what I am looking for, however it is noexcept, which is more than my requirement of "the strong" guarantee. Is appears the "strong guarantee" cannot be tested, but the noexcept guarantee can.

#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);
}

回答1:


Probably impossible:

It is impossible if copy assignment is not noexcept (or other way to perform the copy). In case it is noexcept, std::swap() should do the thing. Otherwise, there is probably nothing one can do about it.




回答2:


@Incomputable has highlighted the problem, but I am including an answer for completeness.

  • There is a class you want to assign but want to make sure there is a strong guarantee that it will be copied completely or not at all in the face of exceptions.. The only feasible solution therefore appears to be a static assert check at compile time to make sure that this will happen. Using std::move is not a guarantee since it can call a copy constructor which may throw, and may also fail to provide the all or nothing guarantee.
  • In my specific case it is a set of configuration objects which must always be valid, and since I can’t guarantee that without checking all the objects manually and hoping the implementors can provide that guarantee, I have written a noecept_assign function which should ensure that is the case going forward. A complete example follows.
#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
}


来源:https://stackoverflow.com/questions/42088173/is-there-facility-for-a-strong-guaranteed-exchange-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!