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

时间:2019-04-05 15:23:19

标签: c++ arrays static allocator

我需要使用自定义分配器初始化的向量的静态数组,以便将我的数据(每个16字节)存储在外部ram中。到目前为止,我已经使用Howard Hinnant short alloc了。

我使用GCC和C ++ 14:

Sequencer.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")));

Sequencer.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个内存池...而且我完全不愿意初始化这些内存数组。

我尝试过这个:

Sequencer.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")));

Sequencer.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) {}

除非向量已被构造,否则我无法更改其分配器,否则我将看不到任何其他解决方案。

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

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类中设置竞技场引用,但到目前为止没有成功。引用不能为null,我不想更改所有我没有使用指针编写的代码,并且通过引用虚拟舞台来初始化FixedVectors会导致相同的初始问题。

谢谢

2 个答案:

答案 0 :(得分:2)

问题是std::vector是分配器is explicit的构造函数。当您执行FixedVector fv{myArena};时,一切都会很好,因为您在此处显式构造了FixedVector。但是使用FixedVector数组,您正在执行list initialization。添加花括号还不够,您需要明确拼出构造函数。

示例演示:

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 :(得分:1)

  1. arena定义move构造函数。您应该具有以下内容:

    // 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多个元素进行硬编码。将它们初始化为默认值(例如为空),然后在循环中分配所需的值会更聪明。您可以围绕静态对象创建包装器结构,并创建其静态实例,然后在struct构造函数中填充数组。可能是这样的:

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;
};