【问题标题】:Static initialization for complex type array复杂类型数组的静态初始化
【发布时间】:2019-04-05 15:23:18
【问题描述】:

我需要使用自定义分配器初始化的静态向量数组,以便将我的数据(每个 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]};

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

编辑

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

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

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

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

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 会导致相同的初始问题。

谢谢,

【问题讨论】:

  • 当您使用FixedVector::allocator_type::arena_type 而不是arena 时会发生什么?
  • 嗨,它不会改变任何东西。我的编译器似乎很好理解发生了什么,我认为这是我不理解的人:)。

标签: c++ arrays static allocator


【解决方案1】:

问题在于std::vector 的构造函数来自分配器is explicit。当您执行FixedVector fv{myArena}; 时,一切都很好,因为您在此处明确构造了FixedVector。但是对于FixedVectors 的数组,你正在做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++ 风格(但这是一个正交问题)。

【讨论】:

    【解决方案2】:
    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&lt;600&gt;,然后将内容移动到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;
    };
    

    【讨论】:

    • 我编辑了我的第一篇文章,不用担心缺少 Sequencer:: 我简化了我的代码,我的别名在 Sequencer 类之外。
    • @zelozelatus 编辑了答案。感谢 Max Langhof 关于显式构造的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多