运算符<<函数的返回值

Return value of operator<< function

本文关键字:lt 返回值 函数 运算符      更新时间:2023-10-16

我知道我应该从"operator<<"返回"ostream&",以便能够像这个一样"链式"运算符

cout<<a<<b<<c;

然而,在下面的代码中,我没有返回"ostream&",并且链接仍然是可能的。为什么?

#include <iostream>
using namespace std;
class CComplexNumber{
    float m_realPart;
    float m_imagPart;
public:
    CComplexNumber(float r,float i):m_realPart(r),m_imagPart(i){}
    friend ostream& operator<<(ostream& lhs,CComplexNumber rhs){
        lhs<<"["<<rhs.m_realPart<<","<<rhs.m_imagPart<<"]"<<endl;
        //MISSING RETURN STATEMENT!
    }
};
int main() {
    CComplexNumber a(1,2);
    CComplexNumber b(3,4);
    CComplexNumber c(5,6);
    cout<<a<<b<<c;
    return 0;
}

输出

[1,2]
[3,4]
[5,6]

从非void函数的末尾脱落是未定义的行为。一种可能的未定义行为是,如果返回到位,它将按预期工作。

g++提供了一个方便的警告,以防止这种情况发生在你身上。

正如其他人所指出的,您已经调用了Undefined Behavior:任何事情都可能发生。如果你运气好的话,你会撞车。看来你运气不好。

如果您对它为什么在这种情况下工作感兴趣,您应该查看生成的程序集。我的即兴猜测是,指向lhs的指针留在了寄存器中,该寄存器在您的平台上返回值。由于C++中的引用通常是用指针实现的,这将具有与向lhs返回引用相同的效果。

但这完全是在黑暗中捅刀子,最终并不是很有趣或重要。只要听编译器的警告,不要那样做。

这是"纯粹的运气"。函数的返回值在特定的寄存器中。由于您现有的代码已经调用了operator<<,因此它会为您返回正确的内容,因此只要在该点之后不涉及其他代码,您就可以从operator<<的内部级别获得返回值。添加一个std::string s = "xyz";"(并在代码中的某个位置使用s),它可能会中断,因为在函数末尾调用的std::string的析构函数"破坏"了operator<<的返回值。因此,依赖它是非常危险的,因为无害的变化会导致它"崩溃"。