为啥赋值运算符和相等运算符之间没有 1:1 的关系?

Posted

技术标签:

【中文标题】为啥赋值运算符和相等运算符之间没有 1:1 的关系?【英文标题】:Why no 1:1 relationship between assignment and equality operators?为什么赋值运算符和相等运算符之间没有 1:1 的关系? 【发布时间】:2017-10-26 18:53:51 【问题描述】:

在下面的代码示例中,因为我比较了两个std::map 对象,所以我不得不实现MyId::operator==()

MyId 是一个简单的类:基本上是一个数组的包装器。这让我想知道为什么要求使用相等运算符:为什么不给我们一个默认的按位比较器?毕竟,我们有一个默认的赋值运算符,它在对象之间进行 bitwise 成员复制。

我了解深拷贝和浅拷贝之间的区别以及需要赋值和相等运算符。我的问题是为什么有默认赋值时没有默认的“按位相等检查”?

#include <iostream>
#include <map>
#include <cstring>

typedef int myid[ 3 ];

struct MyId

  myid id_;
  bool operator<( const struct MyId& other ) const  return this < &other; 
  bool operator==( const struct MyId& other ) const
  
    return ( 0 == std::memcmp( id_, other.id_, sizeof( myid ) ));
  
;

int main( int argc, char* argv[] )

  std::map< MyId, int> map;
  MyId id =  1, 2, 3 ;
  map[ id ] = 5;

  std::map< MyId, int> map2;
  map2[ id ] = 5;

  // This forces implementation of MyId::operator==():
  std::cout << std::boolalpha <<( map == map2 ) << std::endl;

  MyId i1 =  4, 5, 6 ;
  MyId i2 =  7, 8, 9 ;

  // No required implementation of MyId::operator=():
  i1 = i2;

  return 0;

更新:公开更正了我的脑屁 RE:按位与按成员默认赋值运算符。

【问题讨论】:

赋值运算符和复制构造函数进行成员复制 - 不是按位复制。 【参考方案1】:

毕竟,我们有一个默认的赋值运算符,它执行 对象之间的按位复制。

不,它没有。相反,默认的复制赋值运算符的构造方式是复制分配对象的每个成员。根据字段类型中复制赋值运算符的实现方式,结果可能远非按位复制。

无论如何,默认的复制分配(或复制构造,或移动分配,甚至销毁)行为的设计方式是为了满足常见的基本需求。根据语言规范,它在大多数情况下都是可用的,但在已知情况下,语言不确定您的语义,并且需要明确定义这些情况。

相等运算符不同。实际的相等关系不是由语言语法暗示的,而是纯粹由语义暗示的。编译器不知道你如何看到一个类的两个实例“相等” - 因此它要求你告诉他。

【讨论】:

" 默认的复制赋值运算符的构造方式是复制分配对象的每个成员" 你是对的。我的脑袋放屁。 @StoneThrow 我的意思不是指出你的错误,但我实际上是在回答你的问题 :) @iehrlick 明白了,我很尴尬,因为我在发布问题时不记得这一点。 :) 所以我猜你总是会免费获得分配,因为默认实现是一个成员副本,任何类最终都是 POD 的组合,而 POD 显然具有内置分配。因此对象之间的副本将递归地按成员复制,直到到达 POD 副本。那么这只是一个设计决定,无法实现平等吗?好像本来可以的。 @StoneThrow 语言设计者(与编译器开发者一起)讨厌复杂性,他们尽可能避免复杂性。在某些 OO 语言的某些实现中,引入默认的比较运算符在技术上可能是可行的……但这是一个现实。如何默认比较一个没有任何字段的类的两个对象?如何默认比较单个基类的不同派生类的两个对象 - 通过它们的基本引用?是否应该比较 mutable 字段?等等。这将带来一大堆复杂性,而 C++ 本身就充满了。

以上是关于为啥赋值运算符和相等运算符之间没有 1:1 的关系?的主要内容,如果未能解决你的问题,请参考以下文章

关系运算和判断

为啥 ~= 在 C++ 中缺少唯一的非逻辑赋值运算符? [关闭]

java中这个符号“=”是啥意思?

一些赋值运算符在 AngularJS 表达式中不起作用.. 为啥不呢?

为啥在java中不允许没有括号的赋值和布尔运算符

为啥 Java 没有条件与和条件或运算符的复合赋值版本? (&&=, ||=)