从std::array获取对原始数组的引用



获取对std::array底层原始(C)数组的引用的规范方法是什么?

data()方法只返回一个原始指针,这使得它不适合传递到接受对已知大小的原始数组的引用的函数中。

此外,data()返回一个原始指针,而不是对底层原始数组的引用,这是否有充分的理由,或者这只是一个疏忽?

获取std::数组底层raw(C)的规范方法是什么大堆

没有办法获得底层的C数组。

此外,data()返回原始指针而不是对底层原始数组的引用,还是这只是一个疏忽?

这是向后的:std::array没有充分的理由提供底层的C数组。正如您已经说过的,C数组只有在函数引用C数组时才有用(相对于原始指针)。

你上一次使用功能是什么时候

void foo(int (&arr)[5])

我?从不除了获取数组的大小(并拒绝指针)之外,我从未见过一个带有C数组引用参数的函数:

template <class T, std::size_t N>
auto safe_array_size(T (&)[N]) { return N; }

让我们深入了解为什么不使用对数组的参数引用。

对于初学者来说,从带有单独大小参数的C区域指针是传递数组的唯一方法,因为数组到指针的衰减和缺少引用类型。

在C++中,有C数组的替代方案,如std::vectorstd::array。但是,即使你有一个(遗留的)C阵列,你也有两种情况:

  • 如果你把它传递给一个C函数,你就没有引用的选项,所以你只能使用指针+大小
  • 当您想将它传递给C++函数时,惯用的C++方法是传递begin+end指针

首先,begin+end迭代器是通用的,它接受任何类型的容器。但是,当您想避免模板时,引用std::vector并不罕见,所以如果您有C数组,为什么不引用它呢?因为一个很大的缺点:你必须知道阵列的大小:

void foo(int (&arr)[5])

这是非常有限的。

要绕过这一点,你需要将其作为一个模板:

template <std::size N>
void foo(int (&arr)[N])

这超出了避免使用模板的目的,因此您最好使用begin+end模板迭代器。


在某些情况下(例如,仅对具有相同的语义,所以它们不应该是单独的参数)a调用特定的数组大小,并使函数通用没有道理。在这些情况下,指定数组的大小确保安全,因为它只允许在编译时的正确大小;因此它是有利的,而不是"大缺点">

(C和)C++的优点之一是其巨大的适用范围。所以,是的,你总是会发现一些领域以独特的方式使用或需要某种独特的功能。话虽如此,即使在您的示例中,我仍然会回避数组。当你有固定数量的值不应该在语义上分开时,我认为结构在大多数时候都是数组的正确选择(例如glm::mat4而不是float[4])。

但我们不要忘记std::array是什么:C阵列的现代替代品。在分析选项时,我学到了一件事,那就是没有绝对的"比"。总有一个"取决于"。但在这种情况下并非如此:毫无疑问,std::array应该取代接口中的C数组。因此,在需要固定大小容器作为参考参数的罕见情况下,当您已经有了std::array时,鼓励使用C数组是没有意义的。因此,需要公开std::array的底层C数组的唯一有效情况是对于一些具有C数组引用参数的旧库。但我认为,从更大的角度来看,将其添加到界面中是不合理的。新代码应该使用结构(顺便说一下,std::tuple越来越容易被每个标准使用)或std::array

AFAIK,没有直接或类型安全的方法可以做到这一点,但如果您需要传递给一个函数(具有无法更改为std::array的签名),可以通过使用reinterpret_cast来解决,如下所示:

some_function(*reinterpret_cast<int (*)[myarr.size()]>(myarr.data())));

如果你想让它更安全:

#include <array>
void passarray(int (&myarr)[5]){}  
template <typename ValueT, std::size_t size>  
using CArray = ValueT[size];  
template <typename ValueT, std::size_t size>  
CArray<ValueT, size> & c_array_cast(std::array<ValueT, size> & arg)  {
{                                      
return *reinterpret_cast<CArray<ValueT,size>*>(arg.data());  
}  
int main()
{  
std::array<int,5> myarr = { {1,2,3,4,5} };  
passarray(*reinterpret_cast<int (*)[myarr.size()]>(myarr.data()));  
passarray(c_array_cast(myarr));  
return 0;  
}  

没有。

我明白为什么它会很有用,尤其是在处理遗留代码时,但几十年前我们就应该从这样的代码转向迭代器感知算法。在使用C代码时,无论如何都必须使用指针。我认为这些都是决定不提供此功能的因素。

如果可能的话,请重写代码以接受std::array<T, N>&

您可以将reinterpret_cast.data()转换为原始,如:

template <typename T, std::size_t N>
inline static decltype(auto) to_raw_array(const std::array<T, N> & arr_v) {
return reinterpret_cast<const T(&) [N]>(*arr_v.data());
}

但这是一个丑陋的黑客。正如其他人已经建议的那样,我建议您按原样使用std::array

用法:

#include <cstdint>
#include <array>
template <typename T, std::size_t N>
inline static decltype(auto) to_raw_array(const std::array<T, N> & arr_v) {
return reinterpret_cast<const T(&) [N]>(*arr_v.data());
}
void foo(const std::uint8_t(&buf)[5]){
// ...
}
int main(void){
std::array<std::uint8_t, 5> arr = {1,2,3,4,5};
foo(to_raw_array(arr));
}

为什么不通过std::array.begin()?在SDL2工作于:

int SDL_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count)

我要画的线:

std::array<SDL_Point, 8> a_line;

我是这样通过的:

SDL_RenderDrawLines(r_s_game.p_renderer, a_line.begin(), 8);

最新更新