c++操作符重载:用+=实现+

C++ operator overloading: implementing + with +=

本文关键字:实现 操作符 重载 c++      更新时间:2023-10-16

操作符重载

显示以下列方式完成

class X {
  X& operator+=(const X& rhs)
  {
    // actual addition of rhs to *this
    return *this;
  }
};
inline X operator+(X lhs, const X& rhs)
{
  lhs += rhs;
  return lhs;
}

我理解为什么参数lhs需要按值取,但为什么我们需要按值返回它?我的意思是,以下内容有什么问题:

inline X& operator+(X lhs, const X& rhs)
{
  lhs += rhs;
  return lhs;
}

在函数内部,lhs是一个新的X,修改它不会影响两个操作数中的任何一个。因为这是新的,我们可以通过引用返回它,对吗?

返回对本地对象的引用的问题是调用者将在到达时接收到已经死亡的对象。

当你退出一个函数时,所有的局部变量都被销毁,所以你不能继续使用对它们的引用。

代码

const X& res = a+b;
如果操作符按值返回,

可以工作,因为语言中有一个特定的规则,规定绑定到引用的临时对象将保持有效,直到引用本身被销毁。

返回引用是不同的,因为对象的生命周期是被调用操作符的责任,而不是调用者的责任。因此,最终结果将是绑定到一个已经被销毁的对象的引用。

甚至

X res;
res = a+b;

不能工作,因为当操作符调用返回时,对象在对res赋值之前被销毁。复制构造函数X res = a+b;也是如此。

如果您引用的值在退出函数后将不再存在,则永远不要返回引用。

在这种情况下,lhs将一直存在直到函数返回。如果通过引用返回,该引用将"指向"一个不再存在的值,任何使用它的尝试都将导致未定义的行为。

这就是按值返回的原因。但是不用担心,许多编译器可以优化额外的复制,实际上它不是复制而是移动操作,所以即使它没有优化,"重"对象将被移动而不是复制,从c++ 11开始。

不是严格地回答问题,而是帮助理解参考文献…在返回引用时要非常谨慎,除非知道所引用的对象是稳定的。

这样做是不安全的

const std::string& doNothing(const std::string& x) {return x;}

您将在下面所示的第二个调用中断开

std::string baa = "sheep";
std::cout << doNothing(baa) << std::endl;    // works
std::cout << doNothing("goat") << std::endl; // UNSAFE

这是因为第二个调用涉及隐式创建一个临时对象(std::string类型,使用构造函数调用string("goat"))

相比之下,从name() 返回引用是安全的。
class Person
{
  private: std::string _name;
  public: const std::string& name() { return _name; }
  // other constructors and ways to set a _name
};

可以合理地保证类对象(因此它的内部_name)将保留足够长的时间,以便引用对调用者有用。