关于通过引用传递:使用&

Use of the & operator in C++ function signatures

我目前正在阅读加速C++,我意识到我并不真正理解如何在函数签名中工作。

1
int* ptr=#

意味着ptr现在将地址保存到num,但这意味着什么?

1
void DoSomething(string& str)

据我所知,这是一个变量的传递引用(这意味着传递地址),但当我这样做时

1
2
3
4
void DoSomething(string& str)
{
  string copy=str;
}

它创建的是str的一个副本。我认为它会引发一个错误,因为我正试图将指针赋给一个变量。

这里发生了什么?在函数调用中使用*和&;意味着什么?


引用不是指针,尽管它们有相似的用途,但它们是不同的。您可以将引用视为另一个变量的别名,即具有相同地址的第二个变量。它不包含地址本身,只引用与初始化变量相同的内存部分。

所以

1
2
3
4
5
6
7
8
9
10
string s ="Hello, wordl";
string* p = &s; // Here you get an address of s
string& r = s; // Here, r is a reference to s    

s ="Hello, world"; // corrected
assert( s == *p ); // this should be familiar to you, dereferencing a pointer
assert( s == r ); // this will always be true, they are twins, or the same thing rather

string copy1 = *p; // this is to make a copy using a pointer
string copy = r; // this is what you saw, hope now you understand it better.


C++中的EDCOX1×0字符是双重用途的。这可能意味着(至少)

  • 获取值的地址
  • 声明对类型的引用
  • 您在函数签名中引用的用法是2的一个实例。参数string& str是对string实例的引用。这不仅限于函数签名,还可以出现在方法体中。

    1
    2
    3
    4
    void Example() {
      string s1 ="example";
      string& s2 = s1;  // s2 is now a reference to s1
    }

    我建议在引用中签出C++ FAQ条目,因为这是对它们的一个很好的介绍。

    • https://isocpp.org/wiki/faq/references网站


    在加速C++的第10章之前,你不应该知道指针。

    引用为其他地方存在的某个对象创建另一个名称(别名)。就是这样。没有隐藏的指针或地址。别看窗帘后面!

    想想一个叫罗伯特的人

    1
    guy   Robert;

    有时你可能想叫他鲍勃

    1
    guy& Bob = Robert;

    现在鲍勃和罗伯特都指同一个人。你不知道他的地址(或电话号码),只是同一件事的另一个名字。

    在你的职能范围内

    1
    2
    3
    4
    void DoSomething(string& str)
    {
      string copy=str;
    }

    它的工作原理完全相同,str是存在于其他地方的某个字符串的另一个名称。

    不要为这是如何发生的而烦恼,只需将引用视为某个对象的名称即可。编译器必须弄清楚如何连接这些名称,而不必这样做。


    在分配变量的情况下(例如,int* ptr = &value,使用与符号,将返回变量的地址(在这种情况下,返回value的地址)。

    在函数参数中,使用和号意味着要将访问或引用传递给变量内存中的同一物理区域(如果不使用,则发送一个副本)。如果使用星号作为参数的一部分,则指定传递的是一个变量指针,这将实现几乎相同的效果。这里的区别在于,如果使用了一个和号,则可以通过名称直接访问变量,但是如果传递一个指针,则必须遵从该指针以获取和操作实际值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void increase1(int &value) {
       value++;
    }

    void increase2(int *value) {
       (*value)++;
    }

    void increase3(int value) {
       value++;
    }

    请注意,increase3对您传递给它的原始值没有任何作用,因为只发送一份副本:

    1
    2
    3
    4
    5
    6
    7
    int main() {
       int number = 5;
       increase1(number);
       increase2(&number);
       increase3(number);
       return 0;
    }

    3个函数调用结束时,number的值是7,而不是8。


    它是一个允许函数修改传递的字符串的引用,不像普通的字符串参数那样,修改不会影响传递给函数的字符串。

    您经常会看到一个const string类型的参数,这是为了提高性能而进行的,因为内部引用不会创建字符串的副本。


    1
    int* ptr=#

    第一种情况:因为ptr是内存,它存储变量的地址。运算符返回内存中num的地址。

    1
    void DoSomething(string& str)

    第二种情况:与号运算符用于表示变量正在通过引用传递,并且可以由函数更改。

    因此,基本上,&operator根据上下文有两个函数。


    在以下情况下:

    1
    int* ptr=#

    您要声明一个名为ptr的变量,其类型为int *(int指针),并将其值设置为"变量num的地址"(&num)。"addressof"运算符(&返回指针。

    在以下情况下:

    1
    void DoSomething(string& str)

    您要将dosomething()方法的第一个参数声明为"对字符串的引用"类型。实际上,这是C++定义"按需传递"的方式。

    请注意,虽然&运算符在这些情况下的操作类似,但它的操作方式不同。具体来说,当用作运算符时,您要告诉编译器获取指定变量的地址;当用于方法签名时,您要告诉编译器参数是引用。还要注意,"作为引用的参数"位不同于具有作为指针的参数;引用参数(&会自动取消引用,并且不会暴露于方法中存储基础数据的位置;对于指针参数,仍然通过引用传递,但会公开指向存储变量的方法,如果方法未能执行解引用(这种情况比您想象的更频繁),则可能会暴露问题。


    虽然pass-by引用可以由编译器通过将地址作为指针传递来实现,但在语义上它与地址或指针没有任何关系。简单来说,它只是变量的别名。

    C++有很多语法不同的上下文中使用不同语义的情况,这就是这些情况之一。


    你无法从str复制构造copy。是的,str是一个引用,但这并不意味着您不能从它构造另一个对象。在C++中,EDCOX1×0算子是3种事物之一。

  • 定义普通引用变量时,将为对象创建别名。
  • 当您在函数参数中使用它时,它是通过引用传递的——您还创建了一个对象的别名,与副本相关联。在这种情况下,您不会注意到任何不同,因为它基本上是您传递给它的对象。当您传递的对象包含指针等时,它确实会产生影响。
  • &的最后一个(并且大部分与您的情况无关)含义是位与。
  • 另一种考虑引用(尽管有点不正确)的方法是对未引用的指针使用句法糖分。