Russian Qt Forum

Qt => Общие вопросы => Тема начата: vertus от Февраль 05, 2012, 19:38



Название: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 05, 2012, 19:38
Наткулся я в свое программе на ошибку сегментации. Долго копал, пока не выявил толи багу, толи недостаток моих знаний.

Вот простой пример демонстрирующий инцидент:

Код:
#include <QtCore/QCoreApplication>
#include <QVector>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<int> vector;

    qDebug() << "Begin in scope\n";

    for (int i = 0; i < 10; i++)
    {
        vector.push_back(i);
        qDebug() << &(vector[i]);
    }

    qDebug() << "\nEnd in scope\n";

    for (int i = 0; i < 10; i++)
    {
        qDebug() << &(vector[i]);
    }

    return a.exec();
}

Теперь смотрим на вывод. Адресс на первые два элемента в перовом цикле не совпадает с адресом на первые 2 элемента во втором, а остальные адреса совпадают!

WTF???





Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: BRE от Февраль 05, 2012, 19:44
А ты попробуй в цикле выводить еще и адрес начала вектора:
qDebug() << &vector[ 0 ] << &(vector);


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 05, 2012, 19:47
Одинаковый!!!



Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: zenden от Февраль 05, 2012, 19:54
Ну и в чем собственно проблема?
QVector заранее выделяет больше памяти, чем требуется, чтобы избежать накладных расходов при добавлении элементов.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 05, 2012, 19:56
Ну и в чем собственно проблема?
QVector заранее выделяет больше памяти, чем требуется, чтобы избежать накладных расходов при добавлении элементов.

При чем здесь это? В одном месте программы адресс на первые два элемента один, а вдругом месте другой! При этом никаких перестановок не производилось в векторе!


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: BRE от Февраль 05, 2012, 20:08
Ну и в чем собственно проблема?
QVector заранее выделяет больше памяти, чем требуется, чтобы избежать накладных расходов при добавлении элементов.
Скорее наоборот, вектор перераспределяет память заново с копированием элементов.

Вот так, думаю будет виднее:
Код
C++ (Qt)
qDebug() << &vector[ 0 ] << &(vector[i]);


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 05, 2012, 20:16
Ну и в чем собственно проблема?
QVector заранее выделяет больше памяти, чем требуется, чтобы избежать накладных расходов при добавлении элементов.
Скорее наоборот, вектор перераспределяет память заново с копированием элементов.

Вот так, думаю будет виднее:
qDebug() << &vector[ 0 ] << &(vector);


Все равно не понятно. Даже если предположить, что изначальная емкость была меньше десяти элементов, он должен был дополнительно выделить память, а не перераспределить её. Разве не так?


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: BRE от Февраль 05, 2012, 20:21
он должен был дополнительно выделить память, а не перераспределить её. Разве не так?
А ты знаешь средства в C++ для дополнительного выделения памяти?


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 05, 2012, 20:24
он должен был дополнительно выделить память, а не перераспределить её. Разве не так?
А ты знаешь средства в C++ для дополнительного выделения памяти?


Да, я стормозил. С таким раскладом к элементам вектора вообще нельзя обращаться по адресу.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: BRE от Февраль 05, 2012, 20:26
С таким раскладом к элементам вектора вообще нельзя обращаться по адресу.
Если его изменять, то конечно.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: mutineer от Февраль 05, 2012, 23:33
Да, я стормозил. С таким раскладом к элементам вектора вообще нельзя обращаться по адресу.

Конечно нельзя и в документации по векторам (в stl точно, в Qt не помню) это написано


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: pastor от Февраль 06, 2012, 00:02
Цитировать
Unlike plain C++ arrays, QVectors can be resized at any time by calling resize(). If the new size is larger than the old size, QVector might need to reallocate the whole vector. QVector tries to reduce the number of reallocations by preallocating up to twice as much memory as the actual data needs.

QVector::push_back is equivalent to append.
QVector::append is the same as calling resize(size() + 1) and assigning value to the new last element in the vector.

Это все из документации по QVector


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: thechicho от Февраль 06, 2012, 02:13
http://developer.qt.nokia.com/doc/qt-4.8/containers.html


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 06, 2012, 09:48
Всем спасибо, я все понял.

А с QList таких приколов нет? По идее там даже в случае перестановки переназначается указетель на следующий элемент, а сама память не трогается.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: mutineer от Февраль 06, 2012, 11:11
Всем спасибо, я все понял.

А с QList таких приколов нет? По идее там даже в случае перестановки переназначается указетель на следующий элемент, а сама память не трогается.

QList загадочная вещь и ведет себя в зависимости от размера хранимого объекта. QLinkedList ведет себя так, как тебе нужно. Но все равно хранить прямые указатели на элементы контейнера потенциально опасно


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 06, 2012, 11:34
Всем спасибо, я все понял.

А с QList таких приколов нет? По идее там даже в случае перестановки переназначается указетель на следующий элемент, а сама память не трогается.

QList загадочная вещь и ведет себя в зависимости от размера хранимого объекта. QLinkedList ведет себя так, как тебе нужно. Но все равно хранить прямые указатели на элементы контейнера потенциально опасно

Как вариант свой список реализовать тогда.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: mutineer от Февраль 06, 2012, 11:36
ИМХО лучше архитектуру поменять


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 06, 2012, 11:43
ИМХО лучше архитектуру поменять

Тоже вариант, только задача то стандартная.

Есть общее хранилище данных и куча объектов которые содержат некоторые подмножества множества элементов хранилища. Изменять элементы может только хранилище, все остальные могут только их читать.

Соотвественно хранить копии элементов не вариант - нужно синхронизировать данные и памяти потребуется заметно больше.

Qt Implicit Sharing не подходит, уже наелся с ним. Явно нигде не видно что объект передается по ссылке, а вот изменить его запросто где-нибудь можно и забыть потом про это. В итоге опять проблема синхронизации.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: mutineer от Февраль 06, 2012, 12:18
А хранить в контейнерах не сами объекты, а смарт-поинтеры на них не вариант?


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 06, 2012, 13:20
А хранить в контейнерах не сами объекты, а смарт-поинтеры на них не вариант?

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


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: Igors от Февраль 06, 2012, 19:29
А с QList таких приколов нет? По идее там даже в случае перестановки переназначается указетель на следующий элемент, а сама память не трогается.

Код
C++ (Qt)
QList <int> lst1;      // здесь адреса брать чревато
QList <QRect> lst2; // а здесь можно  
 

Если sizeof(T) <= sizeof(void *) (размер элемента не больше размера адреса) то QList ведет себя как QVector, иначе это просто вектор указателей с удобствами


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: KrupaKarlo от Февраль 07, 2012, 07:42
А хранить в контейнерах не сами объекты, а смарт-поинтеры на них не вариант?

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

действительно. Зачем ездить на машине, мало ли аккумулятор сдохнет и еще чего. Буду лучше педали крутить.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: Igors от Февраль 07, 2012, 09:57
действительно. Зачем ездить на машине, мало ли аккумулятор сдохнет и еще чего. Буду лучше педали крутить.
Хмм... ну а что такого уж плохого если сам выделяет - сам освобождает? Будет неск строк больше, но никакой катастрофы

Вообще выбор зависит от размера элемента и частоты/порядка обновления. Вектор экономнее но вставка/удаление тяжелее. Если данные создаются один раз но есть многочисленные ссылки на них, то стандартный подход вектор/массив + хранить ссылки как индексы. Указатели удобны но напр сохранение в файл становится сложнее.


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 07, 2012, 10:00
Если данные создаются один раз но есть многочисленные ссылки на них, то стандартный подход вектор/массив + хранить ссылки как индексы.

А можно пример? Как хранить ссылки как индексы?


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: Igors от Февраль 07, 2012, 10:48
А можно пример? Как хранить ссылки как индексы?
Индекс это просто "номер"

Код
C++ (Qt)
QVector <QPoint3D> mVertex;  // вектор точек
QVector <QVector <int> > mPoly;  // вектор полигонов (хранит индексы)
 
void PrintPoly( int index )
{
const QVector <int> & poly = mPoly[index];  // взяли полигон
printf("poly %d: ", index);
for (int i = 0; i < poly.size(); ++i)  {
 const QPoint3D & pt = mVertex[poly[i]];    // точка полигона
 printf("%.2f, %.2f, %.2f\n", pt.x(), pt.y(), pt.z());
}
}  
 
Ну "вектор векторов" может не самое лучшее, но для начала - нормально


Название: Re: Что за WTF с распределением памяти в QVector?
Отправлено: vertus от Февраль 07, 2012, 11:12
Че то сразу и не догадался до такого простого решения!

Спасибо!