C++ 通过引用返回非频率变量和频率变量的diff btwn函数

C++ 通过引用返回非频率变量和频率变量的diff btwn函数,c++,reference,pass-by-reference,C++,Reference,Pass By Reference,考虑下面的代码 int& func1() { int x = 2; return x; } int& func2(int &x) { return x; } int main() { int x = func1(); cout<<"\n : "<<x; int y = 3; x = func2(y); cout<<"\n : "<<x<<"\n

考虑下面的代码

int& func1() {
    int x = 2;
    return x;
}

int& func2(int &x) {
    return x;
}

int main() {
    int x = func1();
    cout<<"\n : "<<x;
    int y = 3;
    x = func2(y);

    cout<<"\n : "<<x<<"\n";
}
代码运行得非常好,但我对下面列出的几点怀疑:

  • 在func1()中,我返回了一个非_引用变量“x”,但 返回类型是对int的引用,因此转换如何 正在发生以及“x”函数的哪个部分实际返回。

  • 在func1()中,“x”作为引用返回,但作为堆栈变量如何返回引用 可以返回x的值,我的意思是在完成后它将没有意义(I am将此点与逻辑“函数不应返回 内存以静态方式分配

  • 在func1()中,它返回一个非引用变量“x”作为引用 对于int,在func2()中返回一个引用变量“x”,如下所示 引用int.,因为两个“x”的类型不同,但为什么 返回类型相同。


  • 我困惑是因为我试图把C++与C联系在一起,因为一切都很清楚,但是这里主要是由于缺少对变量变量的内存布局描述,所以如果有人能告诉我,那么对

    FUNX中,这是非常有帮助的,你所返回的是对某个事物的引用。这是
    x
    ,它是
    func1
    的本地对象,其生命周期在返回时结束。然后,在
    main
    中,指定所引用变量的内容(
    func1
    x
    ,该变量以根吃蒲公英)来初始化
    main
    的局部变量
    x
    。这是未定义的行为,这意味着允许程序将其解释为它想要的任何内容,格式化硬盘或其他任何内容。(很可能,
    func1
    返回了指向被调用堆栈帧变量的指针,该变量可能仍然包含正确的值,因为当堆栈上的值将被下一次函数调用压碎时,为什么还要费事擦除这些值呢?)无论如何,程序是否会使用其他优化选项编译,它可能会给出另一个答案

    func2
    中,返回的是对某物的引用。这就是
    x
    所指的东西,它指的是
    main
    y
    。然后,将引用变量的值分配给
    main
    x
    ,即
    y

    关于引用的内存布局问题,在C中,指针是内存中的地址。时期无路可逃。在C++中,引用是一个更高级的机制,你可以“引用一些东西”、“谈论一些东西”、“看它就是我在那里”。strong>它们完全可以作为普通指针实现。但作为一种语言概念,它们更易于优化,因为它们是不可变的。(一旦设置了引用,它就不能被更改。它引用了一些东西——甚至是位于无效内存位置的对象)这就是标准没有指定引用存储的原因。为自由优化

    更新:关于您的第一个疑问,
    main
    x
    是一个完整的变量(声明为该变量),而不是一个引用。因此,给它分配任何其他值都不会改变
    y
    的值。在C++中,当您在表达式中评估引用时,如:
    int x = 0;
    int& y = x;
    
    // Right hand side is the evaluation of the reference y
    int z = y;
    
    它被计算为引用变量的值,即
    x
    的值,即
    0
    。而
    z
    是一个不同于
    x
    的变量

    关于第三个疑问,
    func2
    将返回一个参考。当函数声明为返回引用时,它返回的是引用。推荐信是这样写的:“我是那边的另一个”。对于返回值,在汇编器级别,如果函数没有内联并且调用确实发生等等,则
    func1
    func2
    最有可能返回的将是指向引用变量的指针。实际上,在C++中,引用<代码> int <代码>是通过< <代码> int >代码>指针> <代码> */COD>获得的。将前面的示例代码与带有指针的相同代码进行比较

    int x = 0;
    int* const y = &x;
    
    int z = *y;
    
    有了引用,
    &
    *
    将以静默方式出现

    正如您所知,语言中引入了引用来支持运算符重载,尤其是赋值运算符

    // Quizz : what is the type of (b = A(123))? What if it is a 1MB object?
    // What should be the type of the right-hand side of the assignment operator?
    A a, b;
    a = b = A(123);
    

    它不能是一个值,否则将执行非常糟糕的操作(通过副本传递结果)。它必须是某种指针,但不可能是。在某个地方会有
    &
    s或
    *
    s,这取决于您对标准和功能的描述方式。Stroustrup没有发明许多特殊类型系统中的运算符重载,而是决定提供两种正交功能:引用,这是无语法麻烦的不可变指针(和“谈论变量”的类型),以及通过引用完全启用的运算符重载。

    func1
    中,您返回的是对某事物的引用。这是
    x
    ,它是
    func1
    的本地对象,其生命周期在返回时结束。然后,在
    main
    中,指定所引用变量的内容(
    func1
    x
    ,该变量以根吃蒲公英)来初始化
    main
    的局部变量
    x
    。这是未定义的行为,这意味着允许程序将其解释为它想要的任何内容,格式化硬盘或其他任何内容。(最有可能的是,
    func1
    返回被调用堆栈帧变量的指针,该变量可能仍然包含正确的值,因为当堆栈上的值将被下一次函数调用压碎时,为什么还要费事擦除这些值呢?)
    // Quizz : what is the type of (b = A(123))? What if it is a 1MB object?
    // What should be the type of the right-hand side of the assignment operator?
    A a, b;
    a = b = A(123);
    
    void something_cpp(int &x)
    {
        x = 2;
    }
    
    void something_c(int *x)
    {
        *x = 2;
    }
    
    int something[10];
    
    int &something2_cpp(void)
    {
        return something[0];
    }
    
    int main(int argc, char *argv[])
    {
        something2_cpp() = 10;
    }
    
    int something[10];
    
    int *something2_c(void)
    {
        return &something[0];
    }
    
    int main(int argc, char *argv[])
    {
        *something2_c() = 10;
    }