当我使用按引用返回时,我不知道这些代码之间的区别

I don't know the difference between these codes when I use return-by-reference

本文关键字:我不知道 代码 之间 区别 返回 引用      更新时间:2023-10-16

我正在学习面向对象编程。 我不知道这些代码之间的区别。 它们都使用按引用返回,但代码#1运行良好,但代码#2运行不佳。 教授说,当我存储交换函数的返回值时,代码#2有问题,它导致了问题。 但我不知道为什么。

请告诉我为什么以及两个代码的区别。

代码 #1:

#include <iostream>
using namespace std;
struct Pair {
int first;
int second;
};
Pair& swap(Pair&);
int main()
{
Pair p1 = {10, 20};
Pair p2 = swap(p1);
return 0;
}
Pair& swap(Pair& pair)
{
int temp;
temp = pair.first;
pair.first = pair.second;
pair.second = temp;
return pair;
}

代码 #2:

#include <iostream>
using namespace std;
struct Pair {
int first;
int second;
};
Pair& swap(int num1, int num2);
int main()
{
Pair p = swap(10, 20);
return 0;
}
Pair& swap(int num1, int num2)
{
int temp;
temp = num1;
num1 = num2;
num2 = temp;
Pair pair = {num1, num2};
return pair;
}

不同之处在于,在代码 #1 中,main()函数声明变量pair,因此它存在于main()的范围内。在代码 #2 中,swap()函数声明变量pair,因此它仅存在于swap()函数的范围内,一旦您离开交换函数,变量就会被销毁。

首先,您可以避免不必要的代码:

int temp = num1;
num1 = num2;
num2 = temp;
Pair pair = {num1, num2};

为什么要先交换数字,只需创建交换数字的对:

Pair pair = {num2, num1};
//              ^     ^

但是现在让我们考虑一下差异(我删除了与问题无关的所有部分,即实际交换(:

Pair& swap(Pair& pair)
{
return pair;
}

在第一个变体中,您通过引用获得一对。该对必须在外部创建并传递到函数中:

Pair p;  // created outside
swap(p); // swap uses reference to p outside
// p still exists
// swap returns just a reference to the same p it received
// -> you can use it for assignment:
Pair pp = swap(p);

请注意,您的函数交换了它通过引用收到的原始 p,因此 p 和 pp 都包含相同的内容。所以这两个代码片段是等效的:

Pair p;
Pair pp = swap(p);
Pair p;
swap(p); // ignoring the return value
Pair pp = p;

在第二个变体中,您在函数中创建对!

Pair& swap(int num1, int num2)
{
Pair pair = {num1, num2};
return pair;
}

但是该货币对的生命周期随着函数退出而结束。因此,您返回对实际上已被销毁的一对的引用,这会产生未定义的行为

如果您按值接受该对,则会发生完全相同的情况:

Pair& swap(Pair pair) // not a reference -> pair is copied into local variable
{
return pair; // returning reference to local -> undefined behaviour!
}

在所有情况下,您都需要返回局部变量,您需要按值返回它们:

Pair swap(int, int)
{
Pair pair;
return pair; // return by value, value will be copied into target variable
// (actually, due to copy elision, directly written there)
}

如果您不想修改传递给函数的对,则按值返回也很有用(只是为了完整起见,并不是您需要将函数更改为(。但是,然后,您将确保不会修改传递给的对。您可以通过 const 引用接受并在其中创建副本;但是,最简单的方法是按值接受,这会在接收参数时直接创建副本:

Pair swap(Pair pair) // notice: both references dropped
{
return pair;
};

现在,p 和 pp确实不同(当然,假设您实际实现了交换(:

Pair p;
Pair pp = swap(p);

#code2 对仅存在于交换函数范围内

在 #code1 中,您需要一个临时值,因为您可以更改存在对,并且您希望在更改之前保存该值。 在 #code2(让我们忽略主要问题(中,您只需从您获得的价值中形成对

Pair& swap(int num1, int num2)
{
Pair pair = {num1, num2};
return pair;
}

如果你考虑一下,你不会交换对,因为你没有配对。