引用和指向数组的指针有何不同,哪个更可取?

How is a reference and a pointer to an array different from each other and which one is preferable?

我是一名 cpp 初学者,一直在尝试非常基础的知识。我正在探索引用和指针在数组方面有何不同,并写了一个简单的片段。


int main() {
    //char *  c2 = "C";
  //std::cout << &c2<<std::endl;
    //std::cout << *c2<<std::endl;
    int arr[]={21,2,3,4,5,6,7,8,9,10};
    int (&ar)[10]=arr;
    int *ar1=arr;
    std::cout<<"add of arr[0] :"<<&arr[0]<<std::endl;
    std::cout<<"value of ar: "<<ar<<std::endl;
    std::cout<<"value of ar1: "<<ar1<<std::endl;
    std::cout<<"value of *ar: "<<*ar<<std::endl;
    std::cout<<"value of *ar1: "<<*ar1<<std::endl;
    std::cout<<"value of *(ar+1): "<<*(ar+1)<<std::endl;
    std::cout<<"value of *(ar1+1): "<<*(ar1+1)<<std::endl;
    std::cout<<"value of ar[0]: "<<ar[0]<<std::endl;//some garbage value
    std::cout<<"value of ar1[0]: "<<ar1[0]<<std::endl;//some garbage value
    std::cout<<"value of sizeof(ar): "<<sizeof(ar)<<std::endl;
    std::cout<<"value of sizeof(int): "<<sizeof(int)<<std::endl;
    std::cout<<"value of sizeof(arr): "<<sizeof(arr)<<std::endl;
    std::cout<<"value of sizeof(ar1): "<<sizeof(ar1)<<std::endl;
}

以下是此代码的输出:

add of arr[0] :0x7fffe6054ba0
value of ar: 0x7fffe6054ba0
value of ar1: 0x7fffe6054ba0
value of *ar: 21
value of *ar1: 21
value of *(ar+1): 2
value of *(ar1+1): 2
value of ar[0]: 21
value of ar1[0]: 21
value of sizeof(ar): 40
value of sizeof(int): 4
value of sizeof(arr): 40
value of sizeof(ar1): 8

如您所见,我能发现的唯一区别是引用的大小不同于指针的大小。事实上,引用和指针的值都是数组的第一个元素。甚至指针算法对它们两者的工作方式也相同。引用的大小是 int*10,而指针的大小是 8。这里到底发生了什么?这两者有何不同,是否有关于何时使用引用或指针的标准做法?

The size of reference is int*10 vs size of pointer which is 8.

引用是别名,所以引用的大小是int*10,与sizeof(arr)

相同

How are these two different and is there a standard practice as to when to use a reference or a pointer?

当你不需要控制对象的生命周期时,更喜欢使用引用。当您发现引用不能满足您的要求时,我们必须使用指针。

参考与指针:

  • 必须初始化引用
  • 不必初始化指针
  • 引用可以悬空,指针也可以悬空
  • 需要删除控制资源所有权的指针,以避免资源泄漏(我们可以使用智能指针来避免)

您还可以阅读 Google c++ style guide 以获取有关选择 reference vs pointer

的更多信息

一个简单的解释:

指针是一种需要足够大才能存储任何地址的类型。在您的系统上,所需的大小是 8 个字节。您也可以使用指针执行操作,而无需实际更改它指向的变量。 sizeof 不会给出数组的大小,而是指针的大小。请注意 sizeof *ar1 也不应给出大小,它只是给出数组第一个元素的大小,即 int.

引用基本上是指针的语法糖,它具有真正的按引用传递的一些额外功能。对于引用和指针,编译器可以使用引用和指针生成 identical/very 相似的 assembly/machine 代码。比如这两个函数:

int foo(int &bar)
{
    return ++bar;
}
int baz(int *bar)
{
    return ++(*bar);
}

使用 GCC 10.2 和 -O1 生成相同的程序集(使用 Compiler Explorer 检查):

foo(int&):
        mov     eax, DWORD PTR [rdi]
        add     eax, 1
        mov     DWORD PTR [rdi], eax
        ret
baz(int*):
        mov     eax, DWORD PTR [rdi]
        add     eax, 1
        mov     DWORD PTR [rdi], eax
        ret

(生成的程序集对于 -O0-O2-O3 的两个函数也是相同的)

如你所见,一模一样

但是,是的,引用比指针有更多的权力。如您所见,sizeof 给出了数组的实际大小,而对于指针,它只是给出了指针的大小。此外,在 const T &T && 的情况下,引用也可以接受右值,而指针不能。