矢量分配和异常安全

Vector assignment and exception safety

本文关键字:异常 安全 分配      更新时间:2023-10-16

我读过关于异常安全的文章,并提出了以下问题:

在A类中,m_value和m_data应相互一致。但是如果

m_data = data;

throw类不变量将被破坏。

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;
}

我应该用一些复制和交换的变体来保护这个代码吗?在这样的每一行代码中使用复制和交换是一个好的决定吗?或者这个代码可以按原样使用?

这是我的解决方案,但我不确定,我应该使用它,还是它是多余的复杂性:

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);
}

如果ComputeValue可以抛出,那么使用复制和交换习惯用法是为函数提供强大异常安全保障的最简单方法。然而,与其通过const引用传递并在函数中进行复制,不如通过值传递向量,因为如果函数传递了r值,编译器就可以调用move构造函数。

void Set(std::vector<unsigned int> data)
{
    m_value = ComputeValue(data);
    m_data.swap(data);
}

如果ComputeValue不能抛出,那么所有这些麻烦都是不必要的,您可以在计算新值之前将向量(通过const引用传递)分配给成员变量。

关于你的第二个问题,我认为只将函数参数分配给成员变量没有任何好处,前提是A的复制分配运算符提供了强大的异常安全保证(它应该这样做),使用复制和交换习惯用法也很容易实现。