我已阅读有关异常安全的内容并提出以下问题:
在A类中,m_value和m_data应该相互一致。但是如果
m_data = data;
抛出类不变量将被破坏。
class A
{
public:
void Set(const std::vector<unsigned int>& data)
{
m_value = ComputeValue(data);
m_data = data;
}
private:
int m_value; //That should be consistent with vector
std::vector<unsigned int> m_data;
}
我应该使用复制和交换的某些变体保护此代码吗? 在这样的代码行中使用copy和swap是否是一个好的决定,或者这个代码可以原样使用?
这是我的解决方案,但我不确定,我应该使用它还是多余的复杂性:
void Set(const std::vector<unsigned int>& data)
{
std::vector<unsigned int> tmp_data(data);
m_value = ComputeValue(tmp_data);
m_data.swap(tmp_data);
}
附加:
另一个问题: 我应该编写自己的异常安全分配运算符或交换函数,以便可以像这样使用它:
class B
{
public:
SetA(const A& a)
{
A tmp_a(a);
m_a.swap(tmp_a);
}
private:
A m_a;
}
在A级
void A::swap(A& rhs)
{
using std::swap;
swap(m_data, rhs.m_data);
swap(m_value, rhs.m_value);
}
答案 0 :(得分:2)
如果ComputeValue可以抛出,使用复制和交换习惯用法是为函数提供强大的异常安全保证的最简单方法。但是,不是通过const引用传递并在函数中复制,最好按值传递向量,因为这允许编译器在函数传递r值时调用移动构造函数。
void Set(std::vector<unsigned int> data)
{
m_value = ComputeValue(data);
m_data.swap(data);
}
如果ComputeValue不能抛出,那么所有这些麻烦都没有必要,你可以在计算新值之前将向量(由const引用传递)分配给成员变量。
关于你的第二个问题,我认为只是将函数参数赋值给成员变量没有任何好处,前提是A的复制赋值运算符提供强大的异常安全保证(它应该),这也很容易实现复制和交换习语。