关于自增运算符重载 & 输出流运算符cout重载的问题

在学习c++运算符重载问题的时候,我学到了自增运算符重载。其中在后置++重载的时候up主说不能返回引用类型,只能返回类对象
——因为在函数中,先定义个局部变量存++之前的值,然后返回。但是不能返回局部变量的引用导致了必须返回一个类对象——这无可厚非。
但是在调用cout重载后的函数对后置++的类对象进行输出的时候,发现了问题,如下:

#include <iostream>
#include <string>

using namespace std;
class person {
    friend ostream& operator<<(ostream& cout,  person& p);
    //friend ostream& operator<<(ostream& cout, person p);
public:
    person(int a);
    person operator++(int);
private:
    int p_a;
};
person person::operator++(int)// int是占位参数,用以区分前置和后置递增的重载
                              // 不能返回引用,因为后置要返回运算前的值,必须定义一个临时变量并返回它的值,如果返回临时变量的引用会出现问题(见笔记)
{
    person p = *this;
    p_a++;
    return p;
}
person::person(int a) {
    p_a = a;
}
ostream& operator<<(ostream& cout,  person& p) {
//ostream& operator<<(ostream& cout, person p) {
    cout << p.p_a;
    return cout;
}
void test01() {
    person p1(2);

    cout << p1++ << endl;

    cout << p1 << endl;
}
int main()
{
    test01();
}

本来在输出前置++的时候好好地cout函数,在输出后置++的时候报出了错误,导致程序崩溃

img

但是在将函数修改为(第二个参数直接写为值传递)

ostream& operator<<(ostream& cout, person p) {
    cout << p.p_a;
    return cout;
}

或者(第二个参数引用前加了const)

ostream& operator<<(ostream& cout, const person& p) {

    cout << p.p_a;
    return cout;
}

的时候,程序正常运行

请问这是为什么?谢谢大家!

因为 p++ 返回 一个临时对象,一个引用类型无法绑定到临时对象,用const 引用可以绑定临时对象

因为当函数按值返回是,其返回的是一个的临时对象,这个对象是一个右值(rvalue),C++不允许一个非常量左值引用形参(non-const lvalue reference parameter)绑定一个右值实参(rvalue argument)。但是你可以用一个常量左值引用形参(const lvalue reference parameter)去绑定一个临时对象(右值实参),这个临时对象的生命期就被延长至那个引用的生命期,常量左值引用不能修改临时对象。另外你也可以用右值引用(rvalue reference)去绑定一个临时对象(右值),并可以对临时对象进行修改,实现移动语义。

https://en.cppreference.com/w/cpp/language/overload_resolution#Viable_functions

  1. If any parameter has reference type, reference binding is accounted for at this step: if an rvalue argument corresponds to non-const lvalue reference parameter or an lvalue argument corresponds to rvalue reference parameter, the function is not viable.

https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary

Whenever a reference is bound to a temporary object or to a subobject thereof, the lifetime of the temporary object is extended to match the lifetime of the reference

https://en.cppreference.com/w/cpp/language/reference