Domanda

The general guideline when writing classes (using the copy-and-swap idiom) is to provide a non throwing swap member function. (Effective C++, 3rd edition, Item 25 and other resources)

However, what if I cannot provide the nothrow guarantee because my class uses a 3rd party class member that doesn't provide a swap operation?

// Warning: Toy code !!!

class NumberBuffer {
public:
    ...
    void swap(NumberBuffer& rhs);

public:
    float* m_data;
    size_t m_n;
    CString m_desc;
};

void swap(NumberBuffer& lhs, NumberBuffer& rhs) {
    lhs.swap(rhs);
}

void NumberBuffer::swap(NumberBuffer& rhs) {
    using std::swap;
    swap(m_data, rhs.m_data);
    swap(m_n, rhs.m_n);
    swap(m_desc, rhs.m_desc); // could throw if CString IsLocked and out-of-mem
}

CString swap cannot be made no-throw, so there's the off chance the swap could fail.

Note: For rare 3rd party classes, using a smart ptr (pimpl) would be an option, but --

Note: CString is a good example as noone in his right mind (?) would start holding all members of a conceptually simple and ubiquitous class like CString via pimpl (smart ptr) because that would really look horrible -- and on the other hand, there's no (short to mid-term) chance to get the CString modified to allow fully no-throw swap.

So, is it OK to have a potentially throwing swap member function if you can't help it? (Or do you know ways around this conundrum?)

Edit: And: Can a throwing swap member be used with the copy-and-swap idiom to provide the basic guarantee if not the strong guarantee?

È stato utile?

Soluzione

So, is it OK to have a potentially throwing swap member function if you can't help it? (Or do you know ways around this conundrum?)

There is nothing inherently wrong with having a swap function that can potentially throw, but beware that without the strong exception guarantee in swap, it cannot possibly be used to provide exception safety, that is, it can only be used as swap (that is, forget about the copy-and-swap idiom for that particular class as a way of providing the strong exception guarantee... but you can still use it to reduce the amount of code --and document that it is not exception safe)

Alternatively, you can move the CString into a smart pointer that offers a no-throw swap (or at the very least the strong exception guarantee), not a nice solution, but it will at least be exception safe. Lastly, you can move away from CString altogether by using any other string library that provides whatever you need and offers a no-throw swap operation.

Altri suggerimenti

There's nothing inherently wrong with a throwing swap, it is just less useful than a no-throw version.

The copy and swap idiom doesn't need swap to be no-throw in order to provide the strong exception guarantee. swap needs only to provide the strong exception guarantee.

The difficulty is that if the no-throw guarantee cannot be provided, it is also likely that the strong exception guarantee cannot be provided. Naive swapping using a temporary and three copies only provides the basic guarantee unless the copying operation provides the no-throw guarantee, in which case swap is also no-throw.

You can easily make it nothrow:

void NumberBuffer::swap(NumberBuffer& rhs) throw()
{
    try
    {
        std::swap(m_desc, rhs.m_desc);   //could throw
        std::swap(m_data, rhs.m_data);
        std::swap(m_n, rhs.m_n);
    }
    catch(...)
    {
    }
}

Of course, this is no real solution to the problem, but now you at least got your non-throwing swap ;)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top