如果一个函数通过引用返回一个数组,它是指针的衰减吗?

If a function returns an array by reference is it a decay to pointer?

本文关键字:一个 指针 衰减 引用 函数 如果 数组 返回      更新时间:2023-10-16

在下面的示例代码中,ComputeSomething() 返回对数组的引用。

我被要求使用C++核心准则(MSVC 工具链上的 NuGet 包)作为额外的静态分析工具。

ComputeSomething()的返回行上,静态分析工具警告存在指向指针衰减的数组。我认为目的是更改它以使衰减显式(类似于&(computed_values[0])),但这会破坏通过引用返回数组的意义。

对于通过引用返回数组的特定用例,这是一个有效的警告还是噪音?

(假设 C++98 约束)

float (&ComputeSomething( const seed_t(&seed_data)[num_of_elems_seeded] ))[num_of_elems_calculated]{
static float computed_values[num_of_elems_calculated];
// do something...
return computed_values;
}

对于下面的方法:

float (&ComputeSomething())[num_of_elems_calculated]{
static float computed_values[num_of_elems_calculated];
// do something...
return computed_values;
}

与静态分析工具中可能发生的情况不同,数组到指针衰减的潜在变化不是在方法内部确定的,而是在调用方调用函数时确定的:

// expected to decay
float *some_computation = ComputeSomething(); 
// not expected to decay to pointer
float (&safer_computation)[num_of_elems_calculated] = ComputeSomething();

感谢@Galik对此的投入。

是的。

ComputeSomething函数中,computed_values是一个数组。与通常的数组一样,它可以自然衰减到指向其第一个元素的指针。

因此,ComputeSomething函数可以简化为

const float* ComputeSomething(...){ ... }

为了"保留"大小信息,然后能够像现在一样使用该函数,无论如何都需要调用方知道大小。它不是自动传输的东西。因此,使用指针不会有太大变化,除非您绝对想在数组上使用sizeof,但无论如何,使用必须在变量声明中提供的大小可以避免这一点。使用指针肯定会简化语法,因此也使代码更具可读性和可维护性。

您也可以使用std::vector,它具有内置的大小信息。或者强制升级到可以使用 C++11 的更现代的编译器,如果要使用编译时固定大小的数组,请使用std::array

我不确定std::pair是否存在于 C++98 中,或者它是否存在于 C++03 中,但作为某种中间立场,您可以使用std::pair<float*, size_t>来返回指针大小。

最后,您始终可以使用typedef为数组类型创建别名。然后你不需要在任何地方显式指定大小,它会大大简化语法:

typedef computed_values_type[num_of_elems_calculated];
....
computed_values_type& ComputeSomething(...) { ... }
...
computed_values_type& computed_values = ComputeSomething(...);

从编译的二进制文件的角度来看,对数组的引用就像指向第一个元素的旧指针一样。它与原始指针的区别仅在于类型本身,其中包含有关数组大小的信息。例如,它可以用于编译时大小检查、编译器警告或range-based for循环