2011-10-05 40 views
4

编写类(使用copy-and-swap idiom)时的一般指导原则是提供非抛出交换成员函数。 (Effective C++, 3rd edition, Item 25和其他资源)可以使用抛出交换成员实现吗?

但是,如果我不能提供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(平普尔)将是一种选择,但 -

注:CString的是一个很好的例子,在他的脑子没有人会(?)通过pimpl(smart ptr)开始持有像CString这样的概念上简单而无处不在的类的所有成员,因为这看起来真的很糟糕 - 另一方面,没有(短期到中期)机会让CString被修改为允许完全无丢包交换。

那么,如果你不能帮助它,可以使用一个潜在的引用交换成员函数? (或者你知道解决这个难题的方法吗?)

编辑:和:一个投掷交换成员可以使用复制和交换成语提供基本保证,如果不是强有力的保证?

+6

不是一个答案,但如果你可以离开'CString',那么问题就会消失... –

+0

请注意,在类似的问题上,你会有一些相当短的年数当您尝试为您的课程实施C++ 11移动时遇到同样的问题。如果成员不能不交换,那么它有可能不会是不可移动的,因为两者非常相似。 –

回答

3

所以如果你无法提供帮助,可以使用可能的引用交换成员函数吗? (或者你知道解决这个难题的方法?)

没有什么本质上与具有swap功能,可以潜在地抛出,但要注意,如果没有在swap强异常保证,它不可能被使用以提供异常安全性,也就是说,它只能用作swap(也就是说,忘记该特定类的复制和交换习惯用法作为提供强大异常保证的方式......但您仍然可以使用它以减少代码量 - 并证明它不是异常安全的)

或者,您可以将CString变成了一个智能指针,它提供了一个无丢包swap(或者至少是强大的异常保证),这不是一个好的解决方案,但它至少会是异常安全的。最后,你可以通过使用任何其他的字符串库来完全避开CString,它提供了你所需要的任何字符串库,并提供了一个无丢包交换操作。

+0

+1您是否可以从异常安全到线程安全?或者这是一个错字? –

+0

@ChristianRau:考虑到上下文可能的错字......事实上,这是如此明显,我下意识地读*例外*安全:) –

+0

@ChristianRau:这是一个错字,对此感到抱歉。我有点累了:) –

-2

您可以轻松地让它抛出异常:

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(...) 
    { 
    } 
} 

当然,这是没有真正解决问题,但现在你至少有你不抛出交换;)

+1

除了'交换'不履行合同和*默默*失败!愉快的时间找到这些错误!我建议你要么限定你的例子如何*不*做或删除答案。谢谢! –

+0

@Martin这并不意味着太严肃,我意识到评论会更好,但可以随意投票。 –

+1

鉴于'throw()'异常规范,如果没有try/catch,这会更好。这样编译器就会安排'std :: terminate'在被抛出的时候被调用,至少假设你没有处于某种不兼容的MSVC模式。仍然可能不是主叫方想要的,但至少显然有些事情是错误的。 –

2

投掷swap没有什么内在错误,它比没有投掷的版本更有用。

复制和交换成语不需要swap是无投掷,以提供强大的例外保证。 swap只需提供强有力的例外保证。

难点在于,如果无法提供无投票保证,那么很可能无法提供强有力的例外保证。使用临时版本和三份副本进行的天真交换仅提供基本保证,除非复制操作提供了无丢包保证,在这种情况下,swap也是无丢包的。

+0

优秀点wrt。没有丢与强。如果只有一个成员不提供无投票保证,那么这只是交换(复制)的问题,首先要获得强力保证。如果有多个成员,我认为一个人运气不好。 –

相关问题