获取对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::vector
和std::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);