什么是引用指向指针?

What is a reference-to-pointer?

本文关键字:指针 引用 什么      更新时间:2023-10-16

我最近看到一个函数被声明为:

void func(type* &param);

我已经知道type* paramtype& param的区别。以上这些与他们有什么不同?什么时候用呢?这样做明智吗?

上面的操作不仅可以修改指向对象,还可以修改指针本身。例如,考虑下面的代码:

void func(int*& ptr) {
    *ptr = 1;
    ptr = 0;
}
int main() {
    int x = 0;
    int* y = &x;
    func(y);
}

在执行结束时,x的值为1, y的值为0(如您所见)。

请注意,为了示例的缘故,我使用0作为空指针,但如果您使用c++ 11,您可能应该使用nullptr代替(它没有为std::ostream重载operaror<<)。


这个概念可以通过查看下面的代码来理解:

template<class Type> using ptr = Type*;
ptr<int>& x;

std::unique_ptr<int>& x;

在这些例子中,x是对类型(ptr<int>std::unique_ptr<int>)的引用,而类型恰好是具有指针语义(operator*operator->)的指针/类。


关于指针中const限定符的位置,可以做一个可能有趣的题外话。考虑以下两个实例:
  1. void func(const int*& ptr)
  2. void func(int*const& ptr)

它们的含义是:

  1. 指针通过引用一个常量int
  2. 指针,通过常量引用指向int

按照上面与ptr的类比,它们将是:

  1. ptr<const int>&
  2. ptr<int> const&

因此,第一个函数将无法执行函数体中的*ptr = 1(因为int是常量),但将愉快地执行ptr = 0

第二个则相反,允许*ptr = 1(因为指向的int不是常量),而不允许ptr = 0(因为指针是常量)。

当然,对于:

void func(const int*const& ptr)

ptr的类比中是ptr<const int> const&,它们两个都是不允许的。


什么时候用这个?这样做明智吗?

像每一个特性一样,当你需要它的时候,你会发现它很有用。但就像一般的想法一样,有些人使用它来释放动态分配的资源后重置指针(我不推荐这样做,见下文)。

让我们举个例子:

free_my_int(int*& ptr) {
    delete ptr;
    ptr = nullptr;
}
int* x = new int(42);
free_my_int(x);

在执行结束时,x将被正确释放,指针自动设置为nullptr(空指针)。这样做是为了防止由于缺少ptr = nullptr而导致的丑陋的分段错误或"指针释放未分配"错误消息。

但是在c++ 11和c++ 14中,很少使用指针,甚至更少引用指针。指针用于的大多数事情都不能被其他标准结构(例如std::optional, std::unique_ptr, std::shared_ptrstd::reference_wrapper)所取代。

让我们比较这三个选项:

  • void func(type* param); // 'param' is a 'type*' variable
  • void func(type& param); // 'param' is a reference to a 'type' variable
  • void func(type*& param); // 'param' is a reference to a 'type*' variable

void func(type* param)
{
    type x;
    ...
    param = &x;
    // Argument 'param' is regarded as a local variable in this function,
    // so setting 'param = ...' will have no effect outside this function
}
当然,如果您执行*param = ...,那么它影响param所指向的内存的内容。例如,您也可以执行param[5] = ...,并影响该内存空间内的其他区域。
void func(type& param)
{
    type x;
    ...
    param = x;
    // Argument 'param' is regarded as a reference to a variable outside this
    // function, so setting 'param = ...' will effect the referenced variable
}

这里,您将只更改所引用的变量本身,因此它比将函数声明为void func(type* param),然后通过调用func(&param)传递type param的地址更安全。


void func(type*& param)
{
    type x;
    ...
    param = &x;
    // Argument 'param' is regarded as a reference to a variable outside this
    // function, so setting 'param = ...' will effect the referenced variable
}

这类似于将函数声明为void func(type** param),然后通过调用func(&param)传递type* param的地址,但是同样,出于上面提到的原因,它更安全。