简体   繁体   English

在 c++ 中通过引用返回

[英]Return by reference in c++

#include<iostream>
using namespace std;

int& add() {

    static int a;
    a++;
    cout<<"\na="<<a;
    return a;
}

int main {

   int x,y,m;
   int &z = add(); //it behaves as a reference to "a" which is a static variable
   x=add();//why does it work correctly
   y=add();//why does it work correctly
   z++;
   m=add();//why does it work correctly
   cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
   return 0;
}

output:
a=1
a=2
a=3
a=5
x=2
y=3
z=5
m=5

What happens exactly internally for x,y,m & z x,y,m & z内部究竟发生了什么

int main{
    int x,y,m;      // declare three ints:  x,y,m, all unassigned
    int &z = add(); // a is incremented to 1, z is a reference to a
    x=add();        // add() returns a reference to a, x copies the value of a
    y=add();        // same as above
    z++;            // increments a, since z is a reference to a
    m=add();        // same as x and y, copies the value of a
    cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
    return 0;
}

so you call add() three times in a row, which increments a to 1, 2, 3 (and prints the value each time.因此,您连续调用add()三次,这会将a递增到 1、2、3(并每次都打印该值。

z is a reference to the real a . z是对真实a的引用。

x , y , and m are copies of the value of a when the assignment was made. xym是赋值时a的值的副本。 So x is 2, y is 3, we skip 4 by doing z++ , and then m is 5.所以 x 是 2,y 是 3,我们通过z++跳过 4,然后 m 是 5。

int &z = add();

z is a reference to the static variable a . z是对 static 变量a的引用。 From now on, a and z are synonym.从现在开始, az是同义词。 Both of them point to same memory location.它们都指向相同的 memory 位置。

int x;
x = add();

x is an independent memory location. x是一个独立的 memory 位置。 Because of the assignment, x will hold whatever add() returns at the point of calling.由于赋值, x将保存add()在调用时返回的任何内容。 This is how y and m also works.这也是ym的工作方式。

x , y , and m are just variables, so they get whatever value is in a at the time add is called, and that's it. xym只是变量,因此它们在调用add时获取a中的任何值,仅此而已。 If you were to change the values of any of those variables, it would not affect the value of a .如果您要更改任何这些变量的值,它不会影响a的值。 Since z is a reference, it is a "pointer" (in a sense) to the static a variable, so changing z will actually change a .由于z是一个引用,因此它是指向 static a变量的“指针”(在某种意义上),因此更改z实际上会更改a

A reference is another name, an alias, for some object.引用是某些 object 的另一个名称、别名。 It acts like if it was the object.它的行为就像object。

When add() returns a reference to a , it behaves like if the returned value was a .add()返回对a的引用时,它的行为就像返回的值a

So the code所以代码

x = add();

behaves like it had been表现得像以前一样

a++;
x = a;

So it captures the value a has at that moment.所以它捕捉到了a在那个时刻的价值。

On the other hand, the code另一方面,代码

int& z = add();

behaves just like表现得就像

a++;
int& z = a;

Where z becomes another name for a .其中z成为a另一个名称。 Using a or z from now on doesn't matter, it means the same.从现在开始使用az无关紧要,这意味着相同。 There is still only one value, but the value has two names.仍然只有一个值,但该值有两个名称。 We can use either one to to read it or update it.我们可以使用其中任何一个来阅读或更新它。

It's just like when we use Bob to refer to a guy named Robert - another name for the same thing.就像我们用 Bob 来指代一个叫 Robert 的人一样——同一事物的另一个名字。

I believe this is how it works:我相信这是它的工作原理:

References used in context where (a value of) the referenced type is needed are implicitly dereferenced.在需要引用类型(的值)的上下文中使用的引用被隐式取消引用。 This includes (among others):这包括(除其他外):

  • assignment to a variable赋值给变量
  • passing function arguments declared by value通过值声明的 function arguments
  • passing function return values declared by value传递 function 返回值声明的值

In the above contexts, a copy of the referenced value is created.在上述上下文中,创建了引用值的副本。

Wherever a reference is needed, they are treated as references (obviously not dereferenced.) This includes:无论何时需要引用,它们都被视为引用(显然没有取消引用。)这包括:

  • initializing a reference of compatible type初始化兼容类型的引用
  • passing function arguments declared by reference通过引用声明的 function arguments
  • passing function return values if declared by reference如果通过引用声明,则传递 function 返回值

In these contexts, no copy of the referenced value is created.在这些上下文中,不会创建引用值的副本。 The new reference is just a new alias for the existing value.新引用只是现有值的新别名。

The syntax for both of the above contexts is the same, so it requires some effort to see what's going on.上述两个上下文的语法是相同的,因此需要一些努力才能看到发生了什么。

A reference is just a constant pointer, in the sense that you can change the pointed object but you cannot make it to point to something else.引用只是一个常量指针,从某种意义上说,您可以更改指向的 object 但不能使其指向其他内容。

What C++ does is just saving you from adding pointing de-referencing syntax (unary * ) when you need the value and allows using . *所做的只是在您需要该值并允许使用. instead of -> to access members of the pointed-to structured type.而不是->来访问指向的结构化类型的成员。

Note that there is a common anti-pattern in C++ that uses const X& as if that was a smarter way than just X for function parameters.请注意,在 C++ 中有一个常见的反模式,它使用const X&就好像这比 function 参数的X更聪明。 Please never forget that a reference is basically a pointer so the pointed object may change or even disappear while being used ( const doesn't mean the object doesn't change, just that you cannot change it using that reference ).请永远不要忘记引用基本上是一个指针,因此指向的 object 在使用时可能会更改甚至消失( const并不意味着 object 不会更改,只是您无法使用该引用更改它)。

See this answer for a more detailed description of why you should pay attention when using references instead of values.有关使用引用而不是值时应注意的原因的更详细说明,请参阅此答案

Every time you see a reference you should think at least a bit if the object is going to live enough and/or mutate while you are using it.每次您看到参考资料时,您都应该至少考虑一下 object 在您使用它时是否能够存活和/或变异。 In your case the referenced object is a function static, therefore there are no problems with lifetime (function static objects come into existence the first time you enter the scope where they are defined and live until the end of the program). In your case the referenced object is a function static, therefore there are no problems with lifetime (function static objects come into existence the first time you enter the scope where they are defined and live until the end of the program).

Translating your code to what really happens (pointer fiddling) you get将你的代码翻译成你得到的真正发生的事情(指针摆弄)

#include<iostream>
using namespace std;

int* add() {
    static int a;
    a++;
    cout << "\na=" << a;
    return &a; // we're returning a pointer to our static variable
}

int main(int argc, const char *argv[]) {
   int x,y,m;
   int *z = add(); // points to "a" which is a static variable
   x = *add();     // just get the current value of (incremented) a
   y = *add();     // same here, of course now different from x
   (*z)++;         // incrementing a from outside the function (we've a pointer!)
   m = *add();     // once again just reading current incremented value
   cout << "\nx=" << x << "\ny=" << y<< "\nz=" << (*z) << "\nm=" << m;
   return 0;
}

Ok, let's dissect this small program好,我们来剖析一下这个小程序

int& add() 
{
   static int a;
   a++;
   cout<<"\na="<<a;
   return a;
}

static int a declares a variable. static int a 声明一个变量。 Static in this context means that there is only on place to store a and that place is used whenever add is called. Static 在这种情况下意味着只有一个地方可以存储 a 并且每当调用 add 时都会使用该地方。 So a is like a global variable that can only be accessed inside add.所以 a 就像一个全局变量,只能在 add 内部访问。

The return value is a reference.返回值是一个引用。 Most compiler use pointer internally to represent reference.大多数编译器在内部使用指针来表示引用。 What you can see here is that a reference to the static variable a is returned.您可以在这里看到的是返回了对 static 变量 a 的引用。 Anyone can change a once he obtained the reference.一旦获得参考,任何人都可以更改。

The a++ and the cout is straightforward - no further comments here. a++ 和 cout 很简单——这里没有进一步的评论。

int main{
    int x,y,m;      // declare three ints:  x,y,m, all unassigned
    int &z = add(); // a is incremented to 1, z is a reference to a
    x=add();        // add() returns a reference to a, x copies the value of a
    y=add();        // same as above
    z++;            // increments a, since z is a reference to a
    m=add();        // same as x and y, copies the value of a
    cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
    return 0;
}

int &z = add(); int &z = 添加(); calls add - which means that a is incremented.调用 add - 这意味着 a 递增。 z is now an alias for the static variable a since it uses the reference. z 现在是 static 变量 a 的别名,因为它使用引用。 x=add(); x=添加(); increment a again but now copy the value of a since x is not of type int& but of type int.再次增加 a 但现在复制 a 的值,因为 x 不是 int& 类型而是 int 类型。 y - same. y - 相同。 z++: since z is an alias for a - increment a without printing it via cout. z++:因为 z 是 a 的别名 - 增加 a 而不通过 cout 打印它。

m=add(): increment a, copy a int m like x and y. m=add():递增 a,复制一个 int m,如 x 和 y。

The output is straightforward once you understand why x,y,m are copies and z is an alias. output 一旦你理解了为什么 x,y,m 是副本而 z 是别名,就很简单了。

Any questions still open?任何问题仍然悬而未决?

regards问候

Tobias托拜厄斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM