Есть ли способ избежать копирования между и между valarray и массивом? - PullRequest
2 голосов
/ 27 июля 2011

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

Ответы [ 2 ]

1 голос
/ 08 мая 2013

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

В моей системе (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-байтовое выравнивание, может произойти сбой, выполнить неправильные вычисления или просто работать медленно (в зависимости от вашей платформы)
  • (я уверен, что есть еще несколько причин, по которым он не работает)

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

1 голос
/ 27 июля 2011

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

...