Статическая инициализация для массива сложного типа - PullRequest
2 голосов
/ 05 апреля 2019

Мне нужен статический массив векторов, инициализированный с помощью пользовательских распределителей, чтобы хранить мои данные (по 16 байт каждый) во внешнем оперативной памяти.Для этого я использую Говард Хиннант, короткое выделение , пока все хорошо.

Я использую 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, которые перенаправляют на арену в моем случае).Поэтому мне нужно, чтобы они были построены на арене.Каждая арена хранит и выделяет массив во внешней оперативной памяти, а 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 со ссылкой на фиктивную арену приводит к той же самой начальной проблеме.

Спасибо,

Ответы [ 2 ]

2 голосов
/ 08 апреля 2019

Проблема в том, что конструктор std::vector из распределителя является явным .Когда вы делаете FixedVector fv{myArena};, все хорошо, потому что вы явно создаете FixedVector здесь.Но с массивом FixedVector s вы делаете инициализацию списка .Добавление фигурных скобок недостаточно, вам необходимо явно указать конструктор.

Пример для демонстрации:

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 голос
/ 05 апреля 2019
  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. Вы забыли вложенные фигурные скобки

    Edit: и, как указал 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;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...