std::array与C样式数组用于连续内存

std::array vs C-Style array for contiguous memory

本文关键字:用于 连续 内存 数组 array std 样式      更新时间:2023-10-16

这只是一个有趣的实验。。。

我正在尝试制作一个容器,它将固定数量的字节(例如标头(和动态数据块(例如正文(全部保存在一个连续的内存块中。在传统的C编程中,我会将char[0]作为最后一个实例变量,并且会过度分配sizeof(struct) + data_length

这在C++中有效,但我想要更好的。所以我的问题是,std::array是以指针开头的,还是可以用与本机C风格数组相同的方式使用?

下面是一些示例代码。。。

struct pkg_base
{
virtual std::size_t get_body_size() = 0;
virtual void *get_body_ptr() = 0;
};
template<typename _T, std::size_t _N>
struct pkg
: public pkg_base
{
std::uint16_t a;
std::uint16_t b;
std::uint16_t c;
std::array<_T, _N> body{};
std::size_t get_body_size() override
{
return ( body.size() );
}
virtual void *get_body_ptr() override
{
return ( body.data() );
}
};
void _test_package()
{
auto vec = std::vector<std::unique_ptr<pkg_base>>{};
vec.push_back(std::make_unique<pkg<char, 1024>>());
vec.push_back(std::make_unique<pkg<float, 1024>>());
vec.push_back( std::make_unique<pkg<std::string, 1024>>() );
auto const size = vec.front()->get_body_size();
auto const *ptr = static_cast<char *>( vec.front()->get_body_ptr() );
}

所以我的问题是std::数组是以指针开头的,还是可以像本地C风格数组一样使用?

来自文档

此容器是一个聚合类型,其语义与将C样式数组T[N]作为其唯一非静态数据成员的结构相同。

所以里面没有其他数据成员,只有您想要的T[N]数组。

您可以使用sizeof或查看代码来轻松地确认这一点。

顺便说一句,以_[A-Z]开头的名称是为实现保留的,所以您可能不应该调用模板类型参数_T_N

std::array不包含任何指向其他地方的数据的指针,std::array直接在内部保存数据,其中没有任何动态内容。

它被设计为提供类似于标准数组的语义,但具有标准STL容器的一些特性。

它是一个聚合类,主要实现为

namespace std
{
template<typename T, size_t S>
class array
{
T __elems_[S];
}
}

您有array.data(),它已经返回了一个C数组,所以我不了解您的要求。

作为参考,您所指的技术称为flexible array member,不幸的是,它在C++中不支持作为核心功能或标准库函数。我觉得这很令人失望。

std::array是一个经过修饰的C风格数组(有一些成员允许它用作STL容器,如迭代、大小调整、类型内省等(。

我所知道的实现类似于灵活阵列成员的功能的唯一方法是创建一个std::vector<char>,其大小设置为sizeof(header) + <extra bytes for payload>,而不是vector.data()中的placement new标头。您可以将所有这些封装在一个helper类中,为自己节省一些针对多个场景的键入。

我可以建议将类型擦除作为问题的通用解决方案。在现代C++中,除非不可避免,否则有一种远离直接操作原始指针的趋势:

struct common_part{
//declare common data and ctor
protected:
virtual elem* end(){return begin()+size();};
virtual elem *begin()=0 ;
virtual ~common_part()=default;
virtual std::size_t size()=0;
};
template<std::size_t N>
struct instance_type:
common_part{
protected:
void elem* begin() override{return arr;};
void elem* end() override{return arr+N;};
void std::size_t size() override{return N;};
private:
elem arr[N];
};
std::unique_ptr<common_part> ptr {new instance_type<N>{}};