为啥赋值运算符和相等运算符之间没有 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++ 中缺少唯一的非逻辑赋值运算符? [关闭]