【问题标题】:std::array vs C-Style array for contiguous memory用于连续内存的 std::array 与 C 样式数组
【发布时间】:2018-07-13 12:37:54
【问题描述】:

这是一个仅供兴趣的实验......

我正在尝试制作一个容器,该容器在一个连续的内存块中保存固定数量的字节(例如标头)和动态数据块(例如主体)。在传统的 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::array“以指针开头”是什么意思?
  • “这适用于 C++” - 不,它不支持标准 C++ 不允许零大小的数组。
  • 我不会将std::array 定义为“动态数据块”...
  • placement new 是拥有“可变大小类”的方式。
  • @oneiros 据我所知,您已将我数字中的撇号删掉,这是为什么呢?这是有效的代码。

标签: c++ c++11 stl


【解决方案1】:

所以我的问题是 std::array 是否以指针开头,或者它可以以与本机 C 样式数组相同的方式使用?

来自the documentation

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

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

您可以使用sizeof 或查看代码自行确认。

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

【讨论】:

    【解决方案2】:

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

    它旨在提供类似于标准数组的语义,但具有标准 STL 容器的一些特征。

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

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

    你有 array.data() 已经返回一个 C 数组,所以我不明白你的要求。

    【讨论】:

      【解决方案3】:

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

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

      我知道实现类似于灵活数组成员的功能的唯一方法是创建一个std::vector&lt;char&gt;,其大小设置为sizeof(header) + &lt;extra bytes for payload&gt;,而不是vector.data() 中的placement new 标头。您可以将所有这些包装在一个帮助类中,以便为多种场景节省一些输入。

      【讨论】:

        【解决方案4】:

        我可以建议将类型擦除作为您问题的一般解决方案。在现代 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>{}};
        

        【讨论】:

        • 当您不需要多态性时,为什么还要virtual 成员?为此目的,模板绰绰有余。
        • 为了类型擦除。否则,pair{begin,end} 必须声明为公共数据成员并进行特殊处理。运行时多态性是一种更灵活、健壮但紧凑且经济的方法。在代码膨胀的情况下,{begin,end} 的数据成员看起来更好,但最后 dtor 应该是虚拟的,以便在处理时由指针选择正确的 dtor。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-01
        • 2012-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-21
        • 2011-05-24
        相关资源
        最近更新 更多