有关引用数组参数的用处是什么?

时间:2010-02-03 00:59:48

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

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

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到“指向数组的指针何时有用?”讨论了函数参数,所以我认为这不是一个重复的问题。

6 个答案:

答案 0 :(得分:44)

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

实际上,在数组大小固定在编译时的情况下,使用引用到数组(或指向数组的指针)参数声明可以作为主要参数声明,传递数组的首选方法。另一种变体(当允许数组类型衰减为指针类型时)保留用于需要传递运行时大小数组的情况。

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

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!!!

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

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

换句话说,当涉及引用数组(或指向数组)传递时,实际上没有“为什么”的问题。默认情况下,如果在编译时修复了数组大小,则应该自然地使用此方法。当你使用数组传递的“衰减”方法时,应该真正出现“为什么”的问题。 “decayed”方法只能用作传递运行时大小数组的专门技巧。

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

请记住,尽管在实践中编写适用于运行时大小数组的函数通常是有意义的,特别是在涉及通用库级函数时。这些功能更加通用。这意味着通常在现实代码中使用“衰减”方法是有充分理由的。但是,这并不能成为代码的作者在编译时识别数组大小并使用引用时的情况的借口。 - 相应的阵列方法。

答案 1 :(得分:7)

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

答案 2 :(得分:5)

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

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]); - )

答案 3 :(得分: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] 
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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