Russian Qt Forum

Qt => Вопросы новичков => Тема начата: kadavr от Август 08, 2013, 12:27



Название: Работа QVector
Отправлено: kadavr от Август 08, 2013, 12:27
Здравствуйте.

Если способ создать QVector так что бы он работал с уже существующим огромным массивом чисел без копирования. То есть у меня есть С либа которая генерит мне этот массив, но я не хочу работать в С стиле с указателями а хочу работать с этими данными как с вектором. Возможно ли это сделать не копирую блоки памяти? Массив может быть больше мегабайта.


Название: Re: Работа QVector
Отправлено: gorec323 от Август 08, 2013, 12:35
У QVector есть функция
Код:
T *	data ()

Можно ее использовать.


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 12:40
но я ведь не могу заставить указывать этот указатель на мою область памяти, или могу?


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 12:49
Вот пример кода

Код:
pvector_info pinfo = ngGet_Vec_Info();

double * pMyVector = pinfo->v_realdata; //указатель на нужную область памяти

//хотелось бы что то на подобии этого
QVector<double> data(30000, pMyVector);  //!!! нет такого, а хочется

//а потом, например, отсортировать
sort(data);
   


Название: Re: Работа QVector
Отправлено: Igors от Август 08, 2013, 13:13
но я ведь не могу заставить указывать этот указатель на мою область памяти, или могу?
Не можете, контейнер распределяет память сам, нельзя подсунуть ему выделенное, можно только скопировать. Ну и работайте с С массивом, тот же sort.


Название: Re: Работа QVector
Отправлено: gorec323 от Август 08, 2013, 13:14
Вот пример кода

Код:
pvector_info pinfo = ngGet_Vec_Info();

double * pMyVector = pinfo->v_realdata; //указатель на нужную область памяти

//хотелось бы что то на подобии этого
QVector<double> data(30000, pMyVector);  //!!! нет такого, а хочется

//а потом, например, отсортировать
sort(data);
   

Можно что-то вроде :
Код:
double * pMyVector = new double[30000];
QVector<double> data(30000);
data.data() = pMyVector;


Название: Re: Работа QVector
Отправлено: twp от Август 08, 2013, 13:19
Можно что-то вроде :
Код:
double * pMyVector = new double[30000];
QVector<double> data(30000);
data.data() = pMyVector;
Не сработает поскольку data() возвращает только указатель на данные, а чтоб модифицировать внутренний указатель QVector надо возвращать указатель на указатель.

ТС, А если ли возможность модифицировать C либу, чтоб передавать ей уже распределенную память?


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 13:55
Igors и twp спасибо за конкретные ответы.

Модифицировать либу нельзя(теоретически можно, исходники есть и лицензия BSD), но она сильно большая и сложная. В целом задача состоит в том чтобы ее С подобный API обернуть в более безопасный QT подобный, по этому оставлять роботу напрямую с ссылками будет не правильно. Думаю, что нужно писать свой класс Vector который будет внешне идентичен QVector но без возможности изменять размер. Или может быть дать пользователю доступ к памяти через QDataStream или QByteArray, а пользователь пусть сам думает что с ним делать. Но в любом случае, если дальше работать с этим массивом, то Qt захочет сделать копию, наверное этого не избежать. Может быть это не так и страшно, просто у меня контроллерное прошлое и мне плакать хочется когда понимаю что без видимой на то причины будут копироваться 10 мегабайт памяти.


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 14:07
Теперь не могу понять как скопировать массив в QVector без итераций?
Нашел такое решение:

Код:
    std::vector<double> tmpData;
    tmpData.assign(array, array + numberOfElementsInArray);
    myData.fromStdVector(tmpData);

Но здесь по моему аж два копирования(да и выглядит по идиотски), или Qt умнее чем я думаю и не станет копировать второй раз?


Название: Re: Работа QVector
Отправлено: twp от Август 08, 2013, 14:30
по идее один раз
Код
C++ (Qt)
static inline QVector<T> fromStdVector(const std::vector<T> &vector)
{ QVector<T> tmp; tmp.reserve(int(vector.size())); qCopy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
 
можно попробовать и так
Код
C++ (Qt)
myData.reserve(numberOfElementsInArray);
memcpy(myData.data(), array, sizeof(double) * numberOfElementsInArray);
 
Вообще QVector подчиняется imlicit shared, что означает копирование происходит, если вызывается не константный метод QVector и число ссылок на этот объект > 1


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 14:39
про  imlicit shared я читал, но на практике следующий код дает три разный блока памяти:


Код:
                    pvector_info pinfo = ngGet_Vec_Info(*currV);
   
                    std::vector<double> tmpData(pinfo->v_length);
                    tmpData.assign(pinfo->v_realdata, pinfo->v_realdata + pinfo->v_length);
                    QVector<double> data = QVector<double>::fromStdVector(tmpData);
   
                    double * newData = data.data();
                    double * newData2 = tmpData.data();
   
                    msgOut << "value : "  << data[0]<< endl;
                    msgOut << "value located  : "  << (long)pinfo->v_realdata << endl;
                    msgOut << "value 1 located  : "  << (long)newData << endl;
                    msgOut << "value 2 located  : "  << (long)newData2 << endl;

дают результат

Код:
value : 1.38062e-23
value located  : 6683232
value 1 located  : 6812160
value 2 located  : 6812112


Название: Re: Работа QVector
Отправлено: twp от Август 08, 2013, 14:53
все верно, std::vector выделил блок памяти у себя, QVector - у себя и соответственно было 2 копирования - в std::vector и в QVector. По идее через memcpy произойдет только одно быстрое копирование блока памяти.


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 14:54
сделал так:
Код:
                    pvector_info pinfo = ngGet_Vec_Info(*currV);

                    QVector<double> data(pinfo->v_length);
                    memcpy(data.data(), pinfo->v_realdata, pinfo->v_length * sizeof(double));

И успокоился, нужно двигаться дальше. Если будет нужно потом буду оптимизировать.

Всем большое спасибо.

И еще:


Название: Re: Работа QVector
Отправлено: kadavr от Август 08, 2013, 14:58
Извиняюсь не дописал.

Код:
myData.reserve(numberOfElementsInArray);
memcpy(myData.data(), array, sizeof(double) * numberOfElementsInArray);

Так работать не будет, так как была выделена память, но объекты не созданы и счетчик в QVector будет все равно равен нулю.


Название: Re: Работа QVector
Отправлено: twp от Август 08, 2013, 15:08
Вообще я не правильно указал метод, вместо reserve надо resize, что в принципе одно и тоже что QVector<double> data(size);


Название: Re: Работа QVector
Отправлено: m_ax от Август 08, 2013, 16:18
Ещё как вариант, использовать std::unique_ptr, но это не слишком выйгрышный вариант по сравнению с использованием C массива напрямую. Единственное, о освобождении памяти не придётся думать:

Код
C++ (Qt)
   double * arr = new double[100000];
   std::unique_ptr<double[]> ptr(arr);
   std::cout << ptr[0] << std::endl;