复杂类型数组的静态初始化

Static initialization for complex type array

本文关键字:静态 初始化 数组 类型 复杂      更新时间:2023-10-16

我需要使用自定义分配器初始化的矢量静态数组,以便将我的数据(每个 16 字节)存储在外部 ram 中。我使用Howard Hinnant短分配来做到这一点,到目前为止一切顺利。

我使用 GCC 和 C++14:

音序器.h

using FixedVector = std::vector<SequencerNoteEvent, short_alloc<SequencerNoteEvent, kBytesChunkMax, 4>>;
/* memory pool */
static char sequencerNoteEvent[2][600] __attribute__((section(".masection")));
/* Declaration des différentes zones pour chaque vecteur */
static arena<600> arena0 __attribute__((section(".masection")));
static arena<600> arena1 __attribute__((section(".masection")));
/* Declaration des Vectors utilisants les pools */
static FixedVector v0 __attribute__((section(".masection")));
static FixedVector v1 __attribute__((section(".masection")));

音序器.cpp

// ---------------
// STATIC VARIABLE
// ---------------
char Sequencer::sequencerNoteEvent[kMaxChunks][kBytesChunkMax];
arena<kBytesChunkMax> Sequencer::arena0{Sequencer::sequencerNoteEvent[0]};
FixedVector Sequencer::v0{Sequencer::arena0};
arena<kBytesChunkMax> Sequencer::arena1{Sequencer::sequencerNoteEvent[1]};
FixedVector Sequencer::v1{Sequencer::arena1};

我从 2 个内存池开始,但我需要其中的 98304 个......我完全无法初始化这些数组。

我试过这个:

音序器.h

/* Declaration de la memory pool */
static char sequencerNoteEvent[2][600] __attribute__((section(".masection")));
static arena<600> arenaa[2] __attribute__((section(".masection")));
static FixedVector v[2] __attribute__((section(".masection")));

音序器.cpp

arena<600> Sequencer::arenaa[]{Sequencer::sequencerNoteEvent[0], Sequencer::sequencerNoteEvent[1]};
FixedVector Sequencer::v[]{Sequencer::arenaa[0], Sequencer::arenaa[1]};
error: use of deleted function 'arena<N, alignment>::arena(const arena<N, alignment>&) [with unsigned int N = 600; unsigned int alignment = 4]'
arena<kBytesChunkMax> Sequencer::arenaa[]{Sequencer::sequencerNoteEvent[0], Sequencer::sequencerNoteEvent[1]};

如果我允许复制构造函数(这很可能是一个坏主意)

error: conversion from 'arena<600>' to non-scalar type 'pyrapro::FixedVector' {aka 'std::vector<pyrapro::SequencerNoteEvent, short_alloc<pyrapro::SequencerNoteEvent, 600, 4> >'} requested
FixedVector Sequencer::v[]{Sequencer::arenaa[0], Sequencer::arenaa[1]};

有人知道另一种初始化方法吗?

编辑

非常感谢您的回答! 实际上,我需要使用自定义分配器(short_alloc在我的情况下重定向到竞技场)实例化我的向量。所以我需要用竞技场来建造它们。每个竞技场在外部RAM存储器中存储和分配一个阵列,short_alloc是符合标准要求的自定义分配器本身。

short_alloc(arena_type& a) noexcept : a_(a) {}

除非我可以在构建向量后更改矢量的分配器,否则我看不到任何其他解决方案。

竞技场中的移动构造函数解决了我的部分问题,我仍然有:

error: conversion from 'arena<600>' to non-scalar type 'pyrapro::FixedVector' {aka 'std::vector<pyrapro::SequencerNoteEvent, short_alloc<pyrapro::SequencerNoteEvent, 600, 4> >'} requested

当我这样做时:

FixedVector Sequencer::v0{Sequencer::arena0};

我在初始化时调用short_alloc(arena_type&a),这很好。为什么我不能多次这样做?

当然,如果有人有避免这个巨大initializer_list的想法,我正在听!

后来我试图在short_alloc类中设置竞技场参考,但到目前为止没有成功。引用不能为空,我不想更改所有这些我没有用指针编写的代码,并使用对虚拟竞技场的引用来初始化 FixedVectors 会导致相同的初始问题。

谢谢

问题是来自分配器的std::vector构造函数是显式的。当你这样做FixedVector fv{myArena};一切都很好,因为你在这里明确地构建了一个FixedVector。但是对于FixedVector数组,您正在执行列表初始化。添加大括号是不够的,您需要显式拼写构造函数。

演示示例:

using FV = std::vector<int>;
using FVA = FV::allocator_type;
FVA fva[3]{};
//FV fv[]{1, 2, 3}; // error: cannot convert from int to vector<int>
//FV fv[]{{1}, {2}, {3}}; // ok (nested list initialization)
//FV fv[]{fva[0], fva[1], fva[2]}; // error: cannot convert from FVA to FV
FV fv[]{FV{fva[0]}, FV{fva[1]}, FV{fva[2]}}; // ok

https://godbolt.org/z/X9a67T

请注意,这不仅乏味,而且容易导致初始化顺序惨败。更不用说普通数组不是很好的现代C++风格(但这是一个正交问题)。

  1. 定义arena的移动构造函数。你应该有这样的东西:

    // template or something
    class arena {
    public:
    arena(char arr[]) { /*...*/ }
    // I assume you have it like this. It remains.
    arena(const arena&) = delete;
    // Define your move constructor if you don't have one and
    // just move (assign) buffer pointers, etc. from moved instance to this.
    // Same for move assignment operator.
    arena(arena&&) = default;
    arena& operator=(arena&&) = default;
    // ...
    };
    

    然后行

    arena<600> Sequencer::arenaa[]{Sequencer::sequencerNoteEvent[0], Sequencer::sequencerNoteEvent[1]};
    

    会工作。编译器会将列表中的每个元素隐式转换为arena<600>,然后将内容移动到数组元素arenaa

  2. 您忘记了嵌套的大括号

    编辑:正如Max Langhof指出的那样,显式FixedVector构造,因为显式std::vector构造函数具有单个分配器参数。

    FixedVector Sequencer::v[]{Sequencer::arenaa[0], Sequencer::arenaa[1]};
    

    固定:

    FixedVector Sequencer::v[]{FixedVector{Sequencer::arenaa[0]}, FixedVector{Sequencer::arenaa[1]}};
    

在我看来,如果您想在这些数组中拥有超过 9000 个元素而不是 2 个元素,那么在我看来,在初始化中填充您的静态数组似乎毫无用处,据我从您的问题中了解。我认为您不想在这些初始值设定项列表中对 9000 多个元素进行硬编码。使用默认值(例如空)初始化它们,然后在循环中分配所需的值会更聪明。您可以围绕静态创建包装结构并创建其静态实例,然后在结构构造函数中填充数组。像这样的东西可能是:

class Sequencer {
static struct Wrapper {
using FixedVector = std::vector<SequencerNoteEvent>;
char sequencerNoteEvent[2][600];
arena<600> arenaa[2];
FixedVector v[2];
Wrapper() { 
for (int i = 0; i < 2; i++) {
arenaa[i] = arena<600>(sequencerNoteEvent[i]);
v[i].emplace_back(arenaa[i]);
}
}
} s_instance;
};