赋值运算符 - 自赋值

Posted

技术标签:

【中文标题】赋值运算符 - 自赋值【英文标题】: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(普通旧数据)相同...... 【参考方案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)他想使用它,但有一个关于自我分配的问题。 (此外,您的代码有错字。)

以上是关于赋值运算符 - 自赋值的主要内容,如果未能解决你的问题,请参考以下文章

如何为具有自引用指针的类实现复制构造函数/赋值运算符?

我们如何使用 '=' 运算符为 C++ 中的自定义数据类型赋值?

分享------关于复合赋值运算符

C++ 矩阵类 自赋值问题

java运算符

赋值运算符重载有类似的转换(仅在 VS 中)