4

我想知道(只是出于好奇)为什么在 C++ 中不允许运算符重载用于指针。我的意思是这样的:

Vector2d* operator+(Vector2d* a, Vector2d* b) { return new Vector2d(a.x + b.x, a.y + b.y); }

Vector2d* a = new Vector2d(1, 1); 
Vector2d* b = new Vector2d(2, 2); 
Vector2d* c = a + b; 

注意 'a + b' 如何创建一个新的 Vector 对象,然后只将其地址复制到 'c' 中,而不调用复制构造函数。所以它可以解决新的右值引用解决的相同问题。此外,据我所知,它几乎等同于在 C# 中使用运算符重载时发生的情况(但我在这里可能错了,我从未真正使用过 C#),以及为什么在 C# 中不需要右值引用。

的确,右值引用解决方案更好,因为它允许基于堆栈的对象,而这种重载将强制所有 Vector2d 对象都存在于堆上,但是,它似乎在编译器中很容易实现,可能在右值参考出现之前几年。使用自定义分配器,它甚至不会那么慢。

那么这仅仅是因为“最小惊喜”原则而违法,还是还有其他原因?

4

2 回答 2

7

的确,右值引用解决方案更好,因为它允许基于堆栈的对象,而这种重载将强制所有 Vector2d 对象都存在于堆上,但是,它似乎在编译器中很容易实现,可能在右值参考出现之前几年。使用自定义分配器,它甚至不会那么慢。

那么这仅仅是因为“最小惊喜”原则而违法,还是还有其他原因?

  • 它没有正确链接......a + b + c应该怎么做,泄漏内存?
  • 指针算术在 C++ 中已经有了意义……这对于在类型之间保持一致很有用,否则例如算法将无法在对象的容器上正常工作。
  • 按值返回某些东西意味着调用者不需要清理对象:如果它使用空闲存储(堆)来存储实际数据,它将在必要时自动删除它。使始终如一的强大内存使用更容易。

注意 'a + b' 如何创建一个新的 Vector 对象,然后只将其地址复制到 'c' 中,而不调用复制构造函数。所以它可以解决新的右值引用解决的相同问题。

常用的返回值优化也解决了这个问题,帮助编译器安排将返回值直接构造到调用者的缓冲区中。

于 2013-04-11T08:24:10.757 回答
2

主要原因是指针已经为它们定义了一定数量的运算符。如果我有两个 类型为 和 的a变量,并且我写了 ,那么读者就知道他必须寻找重载或隐式转换。如果变量有 type ,读者可能会认为这是指针算术;拥有它意味着其他事情会令人困惑,并且可能会导致出现数组的问题(包括在内部)。bMyTypea - bMyType*a - bMyTypestd::vector

类似的考虑适用于许多其他运营商。C++ 的指导方针是你应该能够扩展语言,但不能改变它。(而且我知道一元&是这条规则的一个例外。)

关于 C#,语言是不同的。在 C# 中,指针不是对象。MyType和之间没有区别 MyType*,指针上也没有运算符。而且 C# 不使用值语义(通常),因为 C++ 中的大多数对象都具有值语义,并且实际上永远不会被动态分配。(如果Vector2d意味着它看起来的意思,它不应该在 C++ 中动态分配。)

于 2013-04-11T08:30:29.973 回答