Есть ли способ избежать копирования между и между valarray и массивом?

У меня есть много данных в списке, скажем, несколько килобайт в каждом элементе, я хотел бы извлечь каждый из них, чтобы выполнить некоторую числовую обработку. Эти данные изначально хранятся как float[]. Поскольку обработка требует большого количества индексации и глобальных вычислений, я думаю, что valarray можно легко программировать. Но если я использую valarray, мне, возможно, придется сначала скопировать из массива в valarray, а затем скопировать обратно в массив. Есть ли способ избежать этого? В любом случае, чтобы позволить мне работать непосредственно над массивами? Или у вас есть лучшие способы решения подобных проблем?

2 ответа

valarray type не предоставляет никакого способа использовать существующий массив для своего хранилища данных; он всегда делает копию для себя. Вместо того, чтобы хранить ваши данные в обычном массиве, сохраняйте значения непосредственно в valarray с самого начала. Вызов v.resize установить размер и либо присвоить ему значения с [] оператор или использовать &v[0] получить указатель на первое значение и использовать его так же, как указатель итератора или буфера - элементы valarray хранятся непрерывно в памяти.

Предупреждение: безобразный хак.

В моей системе (MS Visual Studio) valarray класс определяется так:

template<class _Ty>
class valarray
{
    ...
private:
    _Ty *_Myptr;    // current storage reserved for array
    size_t _Mysize; // current length of sequence
    size_t _Myres;  // length of array
};

Так что я могу создать свой собственный класс с таким же макетом (с хорошим уровнем уверенности):

struct my_valarray_hack
{
    void *_Myptr;
    size_t num_of_elements;
    size_t size_of_buffer;
};

Затем создайте пустой valarray и перезаписать его внутренние переменные, чтобы он указывал на ваши данные.

void do_stuff(float my_data[], size_t size)
{
    valarray<float> my_valarray;
    my_valarray_hack hack = {my_data, size, size};
    my_valarray_hack cleanup;

    assert(sizeof(my_valarray) == sizeof(hack));

    // Save the contents of the object that we are fiddling with
    memcpy(&cleanup, &my_valarray, sizeof(cleanup));

    // Overwrite the object so it points to our array
    memcpy(&my_valarray, &hack, sizeof(hack));

    // Do calculations
    ...

    // Do cleanup (otherwise, it will crash)
    memcpy(&my_valarray, &cleanup, sizeof(cleanup));
    // Destructor is silently invoked here
}

Это не рекомендуемый способ делать вещи; Вы должны рассмотреть это, только если у вас нет другого способа реализовать то, что вы хотите (возможно, даже тогда). Возможные причины, по которым он может потерпеть неудачу:

  • Макет valarray может отличаться в другом режиме компиляции (примеры режимов: отладка / выпуск; разные платформы; разные версии стандартной библиотеки)
  • Если ваши расчеты изменить размер valarray в любом случае, он будет пытаться перераспределить ваш буфер и сбой
  • Если реализация valarray предполагается, что его буфер имеет, например, 16-байтовое выравнивание, может произойти сбой, выполнить неправильные вычисления или просто работать медленно (в зависимости от вашей платформы)
  • (Я уверен, что есть еще несколько причин, чтобы это не сработало)

В любом случае, стандарт описывает это как "неопределенное поведение", поэтому, строго говоря, при использовании этого решения может произойти все что угодно.

Другие вопросы по тегам