数组引用参数有什么用处?

发布于 2024-08-20 01:26:24 字数 643 浏览 7 评论 0原文

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

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

What can you do in the body of foo() ,这是有用的,如果声明是:

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

我发现一个问题,询问如何传递对数组的引用。我想我是在问为什么

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

I recently found some code like this:

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

What can you do in the body of foo() that is useful, that you could not do if the declaration was:

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

I found a question that asks how to pass a reference to an array. I guess I am asking why.

Also, only one answer to "When is pointer to array useful?" discussed function parameters, so I don't think this is a duplicate question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

鸵鸟症 2024-08-27 01:26:24

数组引用参数不允许数组类型衰减为指针类型。即确切的数组类型保留在函数内部。 (例如,您可以对参数使用 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!!!

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

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

换句话说,当涉及到数组引用(或数组指针)传递时,实际上不存在“为什么”问题。如果数组大小在编译时固定,那么默认情况下,只要有可能,您就应该自然地使用此方法。当您使用数组传递的“衰退”方法时,真正应该出现“为什么”问题。 “decayed”方法只应该用作传递运行时大小的数组的专门技巧。

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

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

The reference-to-array parameter does not allow array type to decay to pointer type. i.e. the exact array type remains preserved inside the function. (For example, you can use the sizeof arr / sizeof *arr trick on the parameter and get the element count). The compiler will also perform type checking in order to make sure the array argument type is exactly the same as the array parameter type, i.e. if the parameter is declared as a array of 10 ints, the argument is required to be an array of exactly 10 ints and nothing else.

In fact, in situations when the array size is fixed at compile-time, using a reference-to-array (or pointer-to-array) parameter declarations can be preceived as the primary, preferred way to pass an array. The other variant (when the array type is allowed to decay to pointer type) are reserved for situations when it is necessary to pass arrays of run-time size.

For example, the correct way to pass an array of compile-time size to a function is

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

or

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

An arguably incorrect way would be to use a "decayed" approach

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

The "decayed" approach should be normally reserved for arrays of run-time size and is normally accompanied by the actual size of the array in a separate parameter

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

In other words, there's really no "why" question when it comes to reference-to-array (or pointer-to-array) passing. You are supposed to use this method naturally, by default, whenever you can, if the array size is fixed at compile-time. The "why" question should really arise when you use the "decayed" method of array passing. The "decayed" method is only supposed to be used as a specialized trick for passing arrays of run-time size.

The above is basically a direct consequence of a more generic principle. When you have a "heavy" object of type T, you normally pass it either by pointer T * or by reference T &. Arrays are no exception from this general principle. They have no reason to be.

Keep in mind though that in practice it is often makes sense to write functions that work with arrays of run-time size, especially when it comes to generic, library-level functions. Such functions are more versatile. That means that often there's a good reason to use the "decayed" approach in real life code, Nevertheless, this does not excuse the author of the code from recognizing the situations when the array size is known at compile time and using the reference-to-array method accordingly.

傾旎 2024-08-27 01:26:24

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

One difference is that it's (supposed to be) impossible to pass a null reference. So in theory the function does not need to check if the parameter is null, whereas an int *arr parameter could be passed null.

沧笙踏歌 2024-08-27 01:26:24

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

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

You can write a function template to find out the size of an array at compile time.

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
}

No more sizeof(test) / sizeof(test[0]) for me ;-)

只是我以为 2024-08-27 01:26:24

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

如果声明是 void foo(int arr[]);,你可以在 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] 
}

Shouldn't we also address the words in bold from the question:

What can you do in the body of foo() that is useful, that you could not do if the declaration was void foo(int arr[]);?

The answer is: nothing. Passing an argument by reference allows a function to change its value and pass back this change to the caller. However, it is not possible to change the value of the array as a whole, which would have been a reason to pass it by reference.

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] 
}
老街孤人 2024-08-27 01:26:24

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

You can ensure that the function is only called on int arrays of size 10. That may be useful from a type-checking standpoint.

jJeQQOZ5 2024-08-27 01:26:24

您可以获得有关函数期望的更多语义。

You get more semantic meaning regarding what the function is expecting.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文