【问题标题】:Assignment operator - Self-assignment赋值运算符 - 自赋值
【发布时间】:2011-08-02 06:54:03
【问题描述】:

编译器生成的赋值运算符是否防止自赋值?

class T {

   int x;
public:
   T(int X = 0): x(X) {}
};

int main()
{
   T a(1);
   a = a;
}

即使类成员不是指针类型,我是否总是需要防止自赋值?

【问题讨论】:

  • 不,这没有什么问题。而且我认为没有什么可以“防范”,真的。编辑:您是在谈论复制构造函数吗?
  • 如果没有类成员是指针/智能类型,那么答案是否定的。无需防范它。在这种情况下,行为与 POD(普通旧数据)相同......

标签: c++ assignment-operator


【解决方案1】:

编译器生成的赋值运算符是否防止自赋值?

不,它没有。它仅执行成员方式的复制,其中每个成员都由其自己的赋值运算符(也可能是程序员声明的或编译器生成的)进行复制。

即使类成员不是指针类型,我是否总是需要防止自赋值?

不,如果您的所有类的属性(以及它们的属性)都是POD-types,则您不需要。

在编写您自己的赋值运算符时,如果您希望自己的类在未来得到验证,您可能希望检查自赋值,即使它们不包含任何指针,等等。也可以考虑the copy-and-swap idiom

【讨论】:

  • 添加、删除或更改数据成员无论如何都需要您重新访问 op=(以及其他),因此就未来的验证而言,不必要的自分配检查没有任何好处。
  • @Johnsyweb:添加不必要的自我分配检查也不能保证维护者会做正确的事情,但更可能让知道他们在做什么的人感到困惑。例如:“不必要”在这里很重要,因为复制经常(很少)自分配的类型会从检查中受益,即使它不是绝对必要的。
  • 或者重申:未来的维护者总是能够把事情搞砸,担心他们可能会或可能不会做的事情是没有效率的。保持更新、有用的文档和编写清晰的代码是您所能做的。
  • @Fred Nurk:完全同意。对于“更新的、有用的文档”,我阅读了“单元测试”:-)
  • 如果所有成员(包括基类)都处理自己的任务,那么您将无事可做。编译器将通过依次调用每个成员的运算符/构造函数来生成成员复制和赋值。这很好用。有时人们认为自我分配测试是一种优化,但它也可能是一种悲观化——为所有分配添加额外的检查。如果自赋值非常普遍,也许我们应该看看使用赋值的代码。 :-)
【解决方案2】:

这很容易凭经验检查:

#include <iostream>
struct A {
  void operator=(const A& rhs) {
    if(this==&rhs) std::cout << "Self-assigned\n";
  }
};

struct B {
  A a;
};

int main()
{
  B b;
  b = b;
}

【讨论】:

  • 不错!这无疑展示了 current 编译器的行为。
【解决方案3】:
class T {
    int x;
public:
    T(int X = 0): x(X) {}
// prevent copying
private:
    T& operator=(const T&);
};

【讨论】:

  • 在我看来 cpx 并不想禁用赋值运算符。 (S)他想使用它,但有一个关于自我分配的问题。 (此外,您的代码有错字。)
猜你喜欢
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 2011-11-16
  • 2013-11-30
  • 2015-10-02
  • 2011-05-29
  • 2011-07-29
  • 2012-01-24
相关资源
最近更新 更多