首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >引用引用的地方?

引用引用的地方?
EN

Stack Overflow用户
提问于 2022-05-06 14:18:20
回答 3查看 82关注 0票数 -1

有一个简单的程序

代码语言:javascript
复制
#include <stdio.h>

int counter = 3;

const int& f() {
    return counter++;
}

const int& g() {
    return counter++;
}

const int& h(int w) {
    counter = w;
    return counter;
}

void main()
{
    const int& x = f();
    const int& y = g();
    const int& z = g();
    const int& t = h(123);
    counter = 45678;
    printf("%d %d %d %d", x, y, z, t);
}

为什么它的输出是5 5 5 45678?特别是,为什么x和y是5?如果它们在初始化后仍然连接到计数器,为什么它们不是45679或类似的东西?

EN

回答 3

Stack Overflow用户

发布于 2022-05-06 14:26:08

因为fg所做的后增量。

代码语言:javascript
复制
const int& f() {
    return counter++;
}

const int& g() {
    return counter++;
}

counter++实际上并不返回counter,而是一个由operator++(int)返回的临时int对象。在C++中,opreator++有两种形式。

代码语言:javascript
复制
Type& operator++(); //pre-increment
Type operator++(int); //post-increment

第二个版本中的int参数是一个用于区分调用的虚拟参数,因为不能仅在返回类型上超载,因为您可以看到增量后返回的值,而不是引用,因此您将返回一个临时变量的引用!

你可以看到GCC和Clang的警告,如果你把他们打开。https://godbolt.org/z/f1fMP463a

因此,总的来说,您调用UB,因为您返回的引用是悬空的。你遇到了最坏的情况,看起来很管用。

此外,main必须在C++中返回int

票数 5
EN

Stack Overflow用户

发布于 2022-05-06 14:23:50

您的程序有未定义的行为。fg的返回值在调用它们的语句末尾不再存在,因此xyz在声明后不引用任何内容。

票数 3
EN

Stack Overflow用户

发布于 2022-05-06 14:56:48

就像到目前为止所给出的答案的补充:为什么没有明确的行为?让我们考虑一个假设的operator++实现:

代码语言:javascript
复制
template <typename T>
T& operator++(T& t) // pre-increment:
{
    t = t + 1;
    return t;
}
// should be clear so far...

template <typename T>
T operator++(T& t, int) // post-increment:
{
    // t = t + 1; // cannot do now, how to return the old value then???
    T b = t;      // need to store the value in a backup copy first!
    t = t + 1;    // NOW we can
    return t;     // need to return the OLD value -> cannot return by reference either,
                  // it's a TEMPORARY ...
}

当您现在使用operator++ (它本身返回一个临时的)时,您将返回一个对临时的引用,该引用在返回-未定义的行为之后不再存在。

为什么你现在看到5?纯技术(仍然是UB!):由于fg看上去是相同的,所以它们在被调用时对堆栈的末尾使用相同的偏移量,并且被一个接一个地调用,因此它们都在同一个堆栈端开始存储临时的堆栈地址,这就是引用被绑定到的地方。注意,这最后包含最后一次增量之前的值,因此5,而不是6。h不需要堆栈上的任何附加值,因此那里的值不会被覆盖--只是在执行赋值时是一样的,因此该值仍然保留。如果h出于某种原因使用堆栈本身,您可能会看到完全不同的东西..。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72142992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档