Преобразование массива

Автор: | 6 августа, 2019

Преобразование массива в вектор

Рассмотрим несколько методов преобразование из массива в std::vector. Так же рассмотрим преобразование QByteArray в std::vector и QVector. Для начала рассмотрим преобразования массива в std::vector 

Объявим значения для преобразования:

using  namespace std; 
vector<int> dataVec;
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int); 

std::copy и back_inserter

 // Копирование массива в вектор, используя back_inserter и метод copy
std::copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));

Описание функции:

copy (InputIterator first, InputIterator last, OutputIterator result);

Копирует элементы в диапазоне [first, last) в диапазон, начинающийся с результата. Функция возвращает итератор в конец целевого диапазона (который указывает на элемент, следующий за последним скопированным элементом). Диапазоны не должны перекрываться таким образом, чтобы результат указывал на элемент в диапазоне [first, last).

Описание параметров функции std::copy:

first, last

Итераторы в начальные и конечные позиции в последовательности, которые будут скопированы. Используемый диапазон — [first, last), который содержит все элементы между first и last, включая элемент, на который указывает first, но не элемент, на который указывает last.

result

Вывести итератор в исходную позицию в последовательности назначения. Это не должно указывать ни на один элемент в диапазоне [first, last).

Подробней про back_inserter

Итератор с обратной вставкой — это особый тип выходного итератора, разработанный для того, чтобы позволить алгоритмам, которые обычно перезаписывают элементы (например, копировать), вместо этого автоматически вставлять новые элементы в конец контейнера. Использование оператора присваивания в возвращаемом итераторе приводит к расширению контейнера на один элемент, который инициализируется присвоенным значением. Возвращенный итератор поддерживает все другие типичные операции выходных итераторов, но не имеет никакого эффекта: все назначенные значения вставляются в конец контейнера.

 // Подготовим вектор перед копированием
 dataVec.reserve(dataVec.size() + dataArraySize);
 copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));

Функция memcpy

// С помощью функции memcpy
dataVec.resize(dataVec.size() + dataArraySize);
memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));

Подробней про функцию memcpy

void * memcpy ( void * destination, const void * source, size_t num );

Копирует значения num байтов из местоположения, на которое указывает источник, непосредственно в блок памяти, на который указывает место назначения. Базовый тип объектов, на которые указывают указатели источника и назначения, не имеет значения для этой функции; Результатом является двоичная копия данных. Функция не проверяет наличие какого-либо завершающего нулевого символа в источнике — она всегда копирует ровно num байтов. Чтобы избежать переполнений, размер массивов, на которые указывают параметры назначения и источника, должен составлять не менее num байтов.

Описание параметров функции memcy:

destination

Указатель на массив назначения, в который должно быть скопировано содержимое, с приведением типа к указателю типа void

source

Указатель на источник копируемых данных, приведенный к указателю типа const void

Num

Количество байтов для копирования. size_t — целочисленный тип без знака

vector::insert

// С помощью vector::insert
dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);

Подробней про vector::insert

Вектор расширяется путем вставки новых элементов перед элементом в указанной позиции, эффективно увеличивая размер контейнера на количество вставленных элементов. Это вызывает автоматическое перераспределение выделенного пространства памяти, только если — новый размер вектора превышает текущую емкость вектора. Поскольку векторы используют массив в качестве своего основного хранилища, вставка элементов в позиции, отличные от конца вектора, заставляет контейнер перемещать все элементы, которые были после позиции, в их новые позиции. Как правило, это неэффективная операция по сравнению с операцией, выполняемой для той же операции другими видами контейнеров последовательностей (такими как list или forward_list). Параметры определяют, сколько элементов вставлено и каким значениям они инициализируются

Доступны следующие шаблоны:

iterator insert (const_iterator position, const value_type& val);
iterator insert (const_iterator position, size_type n, const value_type& val);
template <class InputIterator>
iterator insert (const_iterator position, InputIterator first, InputIterator last);
iterator insert (const_iterator position, value_type&& val);
iterator insert (const_iterator position, initializer_list<value_type> il);

Описание параметров:

position

Положение в векторе, где вставляются новые элементы. iterator — это тип члена, определенный как тип итератора с произвольным доступом, который указывает на элементы

val

Значение, которое будет скопировано (или перемещено) во вставленные элементы. Тип элемента value_type — это тип элементов в контейнере, определенный в deque как псевдоним его первого параметра шаблона (T)

n

Количество элементов для вставки. Каждый элемент инициализируется в копию val. Тип члена size_type является целым типом без знака

first, last

Итераторы, задающие диапазон элементов. Копии элементов в диапазоне [first, last) вставляются в позиции (в том же порядке). Диапазон включает все элементы между первым и последним, включая элемент, на который указывает первый, но не тот, на который указывает последний. Аргумент шаблона функции InputIterator должен быть типом итератора ввода, который указывает на элементы типа, из которого могут быть созданы объекты value_type.

il

Объект initializer_list. Копии этих элементов вставляются по месту (в том же порядке). Эти объекты автоматически создаются из списков объявлений инициализатора. Тип элемента value_type — это тип элементов в контейнере, определенный в векторе как псевдоним его первого параметра шаблона (T)

// Метод 5:  vector + vector
 vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
 dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());

Данный способ самый избыточный

Преобразование QByteArray в вектор

Преобразование из QByteArray в std::vector и QVector и обратно

Объявим значения для преобразования:

using  namespace std; 
QByteArray dataArray = "123456789";
vector<char> dataVec;
QVector <char> dataQVec;


// С помощью copy для std::vector
copy(&dataArray.data()[0], &dataArray.data()[dataArray.size()], back_inserter(dataVec));

// С помощью copy для QVector
copy(&dataArray.data()[0], &dataArray.data()[dataArray.size()], back_inserter(dataQVec));


// Memcpy для std::vector
dataVec.resize(dataVec.size() + dataArray.size());
memcpy(&dataVec[dataVec.size() - dataArray.size()], &dataArray.data()[0], dataArray.size() * sizeof(char));

// Memcpy для QVector
dataQVec.resize(dataQVec.size() + dataArray.size());
memcpy(&dataQVec[dataQVec.size() - dataArray.size()], &dataArray.data()[0], dataArray.size() * sizeof(char));

// С помощью insert для std::vector
dataVec.insert(dataVec.begin(), dataArray.begin(), dataArray.end());

// С помощью insert для QVector
 for (int i = 0; i < dataArray.size(); i++)
 dataQVec.insert(i,dataArray.at(i));

Преобразование из std::vector и QVector в QByteArray

// 

//  Метод преобразование типа reinterpret_cast для  std::vector
QByteArray* data = new QByteArray(reinterpret_cast<const char*>(dataVec.data()), dataVec.size());

// Метод преобразование типа reinterpret_cast для  QVector
QByteArray* data = new QByteArray(reinterpret_cast<const char*>(dataQVec.data()), dataQVec.size());

Подробней про reinterpret_cast

reinterpret_cast преобразует любой тип указателя в любой другой тип указателя, даже из не связанных классов. Результатом операции является простая двоичная копия значения из одного указателя в другой. Разрешены все преобразования указателя: ни указанный контент, ни сам тип указателя не проверяются. Он также может приводить указатели к целочисленным типам или от них.

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

Преобразования, которые могут быть выполнены с помощью reinterpret_cast, но не с помощью static_cast, являются операциями низкого уровня, основанными на реинтерпретации двоичных представлений типов, что в большинстве случаев приводит к коду, специфичному для системы,