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