【问题标题】:What is useful about a reference-to-array parameter?对数组的引用参数有什么用?
【发布时间】:2026-01-21 22:40:01
【问题描述】:

我最近发现了一些这样的代码:

typedef int TenInts[10];
void foo(TenInts &arr);

foo() 的正文中你能做什么有用的,如果声明是你不能做的:

void foo(int *arr);    // or,
void foo(int arr[]);   // or,
void foo(int arr[10]); // ?

我发现了一个问how to pass a reference to an array 的问题。我想我在问为什么

另外,只有one answer 表示“指向数组的指针何时有用?”讨论了函数参数,所以我不认为这是一个重复的问题。

【问题讨论】:

    标签: c++ arrays pass-by-reference


    【解决方案1】:

    我们不应该也解决问题中的粗体字吗:

    你可以在 foo() 的主体 中做什么有用,如果声明是 void foo(int arr[]); ?

    答案是:什么都没有。通过引用传递参数允许函数更改其值并将此更改传回给调用者。但是,无法更改整个数组的值,这将是通过引用传递它的原因。

    void foo(int (&arr)[3]) { // reference to an array
       arr = {1, 2 ,3};       // ILLEGAL: array type int[3] is not assignable
       arr = new(int[3]);     // same issue
       arr = arr2;            // same issue, with arr2 global variable of type int[3] 
    }
    

    【讨论】:

      【解决方案2】:

      一个区别是它(假设是)不可能传递空引用。所以理论上函数不需要检查参数是否为null,而int *arr参数可以传递null。

      【讨论】:

      • 实际上这个建议在 Meyer 的“更有效的 C++”中有整章。 “如果参数可以为null,则通过指针传递,否则通过引用传递”.
      • @Vorac:不过,这是过时的建议。我们应该避免使用原始指针,并且想要使参数成为可选参数并不是停止避免使用它们的充分理由。
      【解决方案3】:

      reference-to-array 参数不允许数组类型衰减为指针类型。即确切的数组类型保留在函数内。 (例如,您可以在参数上使用sizeof arr / sizeof *arr 技巧并获取元素计数)。编译器还将执行类型检查,以确保数组参数类型与数组参数类型完全相同,即如果参数声明为 10 个整数的数组,则参数必须是正好 10 个数组整数,仅此而已。

      事实上,在数组大小在编译时固定的情况下,使用数组引用(或数组指针)参数声明可以被视为主要参数,传递数组的首选方式。另一个变体(当数组类型被允许衰减为指针类型时)保留用于需要传递 run-time 大小的数组的情况。

      例如,将编译时大小的数组传递给函数的正确方法是

      void foo(int (&arr)[10]); // reference to an array
      

      void foo(int (*arr)[10]); // pointer to an array
      

      一个可以说是不正确的方法是使用“腐烂”的方法

      void foo(int arr[]); // pointer to an element
      // Bad practice!!!
      

      “衰减”方法通常应为运行时大小的数组保留,并且通常在单独的参数中伴随数组的实际大小

      void foo(int arr[], unsigned n); // pointer to an element
      // Passing a run-time sized array
      

      换句话说,当涉及到数组引用(或数组指针)传递时,真的没有“为什么”的问题。如果数组大小在编译时固定,则默认情况下,您应该自然地使用此方法。当您使用数组传递的“衰减”方法时,应该真正出现“为什么”的问题。 “decayed”方法只应该用作传递运行时大小数组的特殊技巧。

      以上基本上是更通用原则的直接结果。当你有一个T 类型的“重”对象时,你通常通过指针T * 或引用T & 传递它。数组也不例外。他们没有理由这样做。

      请记住,尽管在实践中,编写与运行时大小的数组一起工作的函数通常是有意义的,尤其是在涉及通用库级函数时。这样的功能更加通用。这意味着在现实生活中的代码中通常有充分的理由使用“衰减”方法,然而,这并不能成为代码作者识别在编译时已知数组大小并使用引用的情况的借口-array 方法。

      【讨论】:

      • ...虽然我不同意你上次的编辑。数组是一个“重”对象,但你不能真正按值传递数组,除非你把它放在结构或其他东西中。
      • 对于dynamically allocated arrays-DAA(例如float* dynamicArray = new float[SIZE]();)和statically allocated arrays-SAA(例如int staticArray[SIZE];)的方法是否保持不变?当我对DAAs 使用int (&input)[SIZE] 语法时,它会出错!但它适用于SAA,后来我使用float *DAAs 工作!无论我们使用DAAs or SAAs,任何关于哪种技术(语法正确!)都可以工作的建议。
      • @Dan,在 c++ 中,我读到您不能将数组作为值传递,它将是 passed as a pointer by valuefunc_name(int *)func_name(int [])passed as a pointer by referencefunc_name(int *&) .此外,在所有情况下,指针都“引用”您的数组。那么,您能否解释一下heavy 对象的含义?此外,然后输入struct,您正在创建对该对象的引用,您将通过引用传递该对象!如果我错了,请随时纠正我!
      • @anu:您不能将 array 作为“作为引用 func_name(int *&) 的指针”传递。只有指针可以这样传递。在您使用“DAA”的示例中,您的 dynamicArray 是一个指针,而不是一个数组。 int (&input)[SIZE] 无法使用它。
      • @AnT,但我能够运行该程序,使用 this 在那里我了解了 func_name(int *&) 例如 void reverse(float *&input, short start, short stop);DDA 创建为`float* dynamicArray = new float[SIZE]();`!
      【解决方案4】:

      你可以编写一个函数模板在编译时找出数组的大小。

      template<class E, size_t size>
      size_t array_size(E(&)[size])
      {
          return size;
      }
      
      int main()
      {
          int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
          std::cout << array_size(test) << std::endl; // prints 8
      }
      

      我不再需要sizeof(test) / sizeof(test[0]) ;-)

      【讨论】:

      • sizeof() 解决方案提供了编译时间常数,而您的模板函数没有(除非您使用 C++0x 添加 constexpr)。参见例如在这里寻求解决方案:*.com/questions/1500363/…
      【解决方案5】:

      你会得到更多关于函数期望的语义含义。

      【讨论】:

        【解决方案6】:

        您可以确保仅在大小为 10 的 int 数组上调用该函数。从类型检查的角度来看,这可能很有用。

        【讨论】: