如何禁止赋值操作

11

对于operator=,使用“canonical”签名有什么原因吗?

class X {
  X& operator=(const X&) = delete;
  X& operator=(X&&) = delete;
};

仅仅是而已

class X {
  void operator=(X) = delete;
};

当你只想做的就是删除它时,该怎么办?

更新:
此外,请考虑X具有明确声明的移动或复制构造函数的情况。

class X {
public:
  X(X&&);
};

在这种情况下,op=(X&&)op=(const X&)被隐式删除了,但是我想明确表达赋值操作是不允许的。


2
在第一个示例中,为什么需要同时删除复制和移动赋值运算符?仅使用X& operator=(const X&) = delete;就足够了,不是吗?由于存在用户声明的复制赋值运算符,移动赋值运算符不会被隐式声明。 - Praetorian
4
作为指导方针,永远不要删除特殊移动成员。如果这样做,最好的结果是你创造了多余的噪音。最糟糕的情况是它无法达到你的期望。X& operator=(const X&) = delete; 足够简洁明了。 - Howard Hinnant
2
@DietmarKühl:是的,功能相同。但并不更简洁(两者都是一行代码)。而且可读性值得商榷,因为X& operator=(const X&) = delete;更常见/熟悉,所以读者必须停下来想一想为什么这个签名不同寻常。最终,这归结为一个风格问题,我建议使用X& operator=(const X&) = delete; - Howard Hinnant
2
把这个贴在你的显示器上,直到你记住它:https://dev59.com/VmAf5IYBdhLWcg3wukpk#24512883 :-) - Howard Hinnant
1
并对所有6个特殊成员进行单元测试,无论您是否拥有它们,就像这样:https://github.com/HowardHinnant/date/blob/master/test/date_test/day.pass.cpp#L62-L67 - Howard Hinnant
显示剩余7条评论
1个回答

6

没有技术上的理由使用规范的拷贝赋值运算符签名。

如标准中所示,[dcl.fct.def.delete] §8.4.3:

  1. 隐式或显式地引用已删除的函数(仅用于声明)的程序是不合法的。 [注意:这包括隐式或显式调用该函数,并形成指向该函数的指针或指向成员的指针。即使在不可能评估的表达式中也适用。 如果函数是重载的,则只有当函数被重载决议选择时才会引用。 ——注释]

因此,在这种情况下,删除函数的名称,即operator=,只能在编译器找到更好的重载解析时使用。然而,这样的重载是不存在的,因为Xconst X&作为参数是无法区分的([over.ics.rank] §13.3.3.2),并且返回值会被忽略。

话虽如此,使用规范的签名有一个风格上的理由。这个问题存在的事实表明,任何阅读你的代码的人都可能不知道它的含义并认为它正在执行某些特殊的功能。为了可读性,我建议你使用熟悉的X& operator=(const X&) = delete;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接