在下面的示例代码中,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
循环