Re: Implementing swap()



Matteo Settenvini <matteo member fsf org> writes:

Murray Cumming <murrayc murrayc com> writes:

And, should we implement swap() using std::swap() on the member
variables, or even std::move() on the member variables?

It depends. If everything is noexcept, I'd say it's quite the same. If
something can throw an exception, it needs to be done by e.g. swapping
tuples, so that it is guaranteed that the object is not left in an
inconsistent state. For instance, this is dangerous [1]:

void C::swap(C& that)
{
    using std::swap; // needed to allow Koenig lookup rules to apply
    swap(this->a, that.a);
    swap(this->b, that.b); // throws
    swap(this->c, that.c);
}

Then when catching the exception, "this" and "that" will have had their
first member swapped, but not the other two fields.


I wanted to follow up my previous post with a simpler solution using
variadic templates. This makes relatively easy to implement a safer
version of swap with rollback semantics.

Code follows.

Cheers,
Matteo


#include <exception>
#include <iostream>
#include <tuple>
#include <utility>

inline void
safer_swap ()
{
        return;    
}

template<typename T, typename... Rest>
inline void
safer_swap (T& a, T& b, Rest... cdr)
{
        using std::swap;
        swap (a, b);
        try
        {
                safer_swap (cdr...);
        }
        catch (...)
        {
                swap (a, b);
                throw;
        }
}


namespace ns
{
        class Throwing
        {
        public:
                Throwing() = default;

                Throwing(const Throwing&)
                {
                        throw std::runtime_error("");
                }
        };


        class Swapper
        {
        public:
                int a;
                Throwing b;
                int c;

                void swap(Swapper& that)
                {
                        safer_swap (a, that.a,
                                    b, that.b,
                                    c, that.c);
                }       
        };
        
} // ~ namespace ns;


namespace std
{
        template<>
        void swap(::ns::Swapper& a, ::ns::Swapper& b)
             noexcept(noexcept(a.swap(b)))
        {
                a.swap(b);
        }

}


int 
main()
{
        ns::Swapper a, b;
        a.a = a.c = 1; 
        b.a = b.c = 2;
        try
        {
                std::swap(a, b);
        }
        catch(std::runtime_error&)
        {
                std::cout << "(" << a.a << ", " << a.c << ") vs. "
                          << "(" << b.a << ", " << b.c << ")" << std::endl;
        }
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]