C++ 有一个抛出交换成员实现可以吗?

C++ 有一个抛出交换成员实现可以吗?,c++,swap,exception-safe,copy-and-swap,exception-safety,C++,Swap,Exception Safe,Copy And Swap,Exception Safety,在使用复制和交换习惯用法编写类时,一般的指导原则是提供一个非抛出交换成员函数。和其他资源 但是,如果因为我的类使用了不提供交换操作的第三方类成员而无法提供nothrow保证,该怎么办 // Warning: Toy code !!! class NumberBuffer { public: ... void swap(NumberBuffer& rhs); public: float* m_data; size_t m_n; CString m

在使用复制和交换习惯用法编写类时,一般的指导原则是提供一个非抛出交换成员函数。和其他资源

但是,如果因为我的类使用了不提供交换操作的第三方类成员而无法提供nothrow保证,该怎么办

// 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交换不能不抛出,因此交换失败的可能性很小

注意:对于罕见的第三方类,可以选择使用智能ptr pimpl,但是-

注意:CString是一个很好的例子,因为没有一个头脑正常的人会通过pimpl smart ptr开始持有概念简单且无处不在的类(如CString)的所有成员,因为这看起来真的很可怕——另一方面,没有短期到中期的机会修改CString以允许完全无抛出交换

所以,如果你不能帮助的话,有一个潜在的抛出交换成员函数可以吗?或者你知道解决这个难题的方法吗


编辑:和:如果不是强有力的保证,抛出式交换成员是否可以与复制和交换习惯用法一起使用以提供基本保证?

您可以轻松地将其设置为其他行:

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(...)
    {
    }
}
当然,这并不是问题的真正解决办法,但现在你至少得到了你的非投掷交换

所以,如果你不能帮助的话,有一个潜在的抛出交换成员函数可以吗?或者你知道解决这个难题的方法吗

具有可能抛出的交换函数本身并没有什么错,但请注意,如果交换中没有强大的异常保证,它就不可能用于提供异常安全,也就是说,它只能用作交换,忘记那个特定类的复制和交换习惯用法,它是提供强异常保证的一种方式。。。但您仍然可以使用它来减少代码量,并记录它不是异常安全的


或者,您可以将CString移动到一个智能指针中,该指针提供无抛出交换,或者至少提供强异常保证,这不是一个好的解决方案,但至少是异常安全的。最后,通过使用任何其他字符串库,您可以完全摆脱CString,这些字符串库提供您需要的任何内容,并提供无抛出交换操作。

抛出交换本身没有什么问题,只是不如无抛出版本有用

为了提供强大的异常保证,复制和交换习惯用法不需要将swap设置为no-throw。掉期只需提供强有力的例外担保


困难在于,如果不能提供no-throw保证,那么也很可能无法提供强异常保证。使用临时副本和三个副本的简单交换只能提供基本保证,除非复制操作提供了不抛出保证,在这种情况下,交换也是不抛出的。

不是答案,但如果您可以远离CString,那么问题就会消失……请注意,在类似的主题上,在相当短的一段时间内,当您尝试为您的类实现C++11 move时,您将遇到同样的问题。如果这个成员不能被交换,那么它也不会被移动,因为这两者非常相似。+1你能从异常安全性到线程安全性建立一点联系吗?或者这是一个打字错误?@ChristianRau:考虑到上下文,可能是打字错误。。。事实上,很明显,我下意识地读到了异常安全:@ChristianRau:这是一个打字错误,很抱歉。我有点累了:大卫-是的,没有强有力的保证,就我所见,也没有基本的保证,除非你非常小心。你怎么认为?这种交换可以用在复制和交换习惯用法中吗?还是必须添加一些try-catch-return来提供基本的保证?也许你可以编辑你的答案,把它包括进去。@Martin:你说得对,这个交换不能用来提供任何例外保证。基本保证可以通过包装在try/catch中来实现,但这与任何随机代码段基本相同……只是交换没有履行其契约,并且悄悄地失败了!很高兴能找到这些错误!我建议你要么将你的例子限定为如何不做,要么删除答案。谢谢@Martin这并不意味着太严肃,我意识到发表评论会更好,但请随意否决。考虑到抛出异常规范,如果没有try/catch,这会更好。这样,编译器将安排在抛出std::terminate时调用std::terminate,至少前提是您没有处于MSVC的不兼容模式。可能仍然不是打电话的人想要的,但至少很明显出了问题。这并不意味着太严重,在我看来很明显。有一个有趣的按钮吗?如/.优秀分数wrt。没有投掷和强壮。如果只有一个成员不提供免抛出保证,那么这只是交换的问题 为了得到强有力的保证,我们必须先复制它。如果有一个以上的成员,我认为有一个是不走运的。