c++ - "checking for self-assignment"有什么问题,它是什么意思?

标签 c++ exception-handling assignment-operator exception-safety

在 Herb Sutter 的书 Exceptional C++ (1999) 中,他在第 10 项的解决方案中有一句话:

"Exception-unsafe" and "poor design" go hand in hand. If a piece of code isn't exception-safe, that's generally okay and can simply be fixed. But if a piece of code cannot be made exception-safe because of its underlying design, that almost always is a signal of its poor design.

Example 1: A function with two different responsibilities is difficult to make exception-safe.

Example 2: A copy assignment operator that is written in such a way that it must check for self-assignment is probably not strongly exception-safe either

他所说的“检查 self 分配”是什么意思?

[查询]

Dave 和 AndreyT 准确地向我们展示了“检查 self 分配”的含义。那挺好的。但问题还没有结束。为什么“检查 self 分配”会损害“异常安全”(根据 Hurb Sutter 的说法)?如果调用者尝试进行自分配,则该“检查”就像没有发生分配一样工作。真的很痛吗?

[MEMO 1] 在 Herb 书中后面的第 38 条对象身份中,他解释了 self 分配。

最佳答案

在这种情况下更重要的问题是:


  • “这是什么意思,当你以某种方式编写函数时,需要你检查自赋值???”

回答我的反问:这意味着设计良好的赋值运算符不需要检查自赋值。将对象分配给自身应该可以正常工作(即具有“什么都不做”的最终效果),而无需对自分配执行显式检查。

例如,如果我想实现一个简单的数组类

class array {
    // code...
 
    int *data;
    size_t n;
};

...并提出了赋值运算符的以下实现...

array &array::operator =(const array &rhs) 
{
    delete[] data;

    n = rhs.n;
    data = new int[n];

    std::copy_n(rhs.data, n, data);

    return *this;
}
这种实现会被认为是“糟糕的”,因为它在自分配的情况下显然会失败。

为了“解决”这个问题,您有两个选择;

  1. 添加显式自分配检查
array &array::operator =(const array &rhs) {
    if (&rhs != this) {
        delete[] data;

        n = rhs.n;
        data = new int[n];

        std::copy_n(rhs.data, n, data);
    }
    return *this;
}
  1. 遵循“无检查”方法:
array &array::operator =(const array &rhs) {
      size_t new_n = rhs.n;
      int *new_data = new int[new_n];

      std::copy_n(rhs.data, new_n, new_data);

      delete[] data;

      n = new_n;
      data = new_data;

      return *this;
}

后一种方法在某种意义上更好,因为它可以在自分配情况下正常工作,而无需进行显式检查。从'安全的角度'来看,这个实现远非完美,这里是为了说明处理自分配的“检查”和“无检查”方法之间的区别。通过众所周知的copy-and-swap idiom,可以更优雅地编写后面的无检查实现。

这并不意味着您应该避免对自分配进行显式检查。从性能的角度来看,这样的检查确实有意义:为了最终“什么都不做”而执行一长串操作是没有意义的。但在设计良好的赋值运算符中,从正确性的角度来看,此类检查不是必需的。

关于c++ - "checking for self-assignment"有什么问题,它是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12015156/

相关文章:

c++ - 将 jsoncpp 外部库添加到我的 qt 项目 : (symbol(s) not found for architecture x86_64)

c++ - 使用 Microsoft Visual Studio 运行 C++ "hello world"程序的最小安装?

c++ - 是否可以使用调试器调试 UnhandledExceptionFilters?

java - 为什么 Java 的 +=、-=、*=、/= 复合赋值运算符不需要将 long 转换为 int?

c++ - std::unordered_map 分配、插入和释放时间

c++ - 编译python3.2 C模块,链接器要求 'python26.lib'

c++ - 如何抛出好的异常?

asp.net - Application_error函数间歇性地捕获 "File does not exist"

c++ - 在堆栈上声明对象的两种方式之间的区别

c++ - 为什么非成员函数不能用于重载赋值运算符?