Russian Qt Forum
Сентябрь 30, 2024, 12:37 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Как правильно работать с контейнером QList?  (Прочитано 6772 раз)
GrieVeR-13
Гость
« : Апрель 03, 2015, 11:17 »

Здравствуйте.
Сегодня натолкнулся на неприятную проблему.
В моей программе в объекте класса
Код:
QList<MyClass> myClassList
хранится около 15к объектов.
В некоторый момент времени мне понадобилось хранить указатель на один из объектов в листе
Код:
MyClass *ptr = &myClassList[0]
Обнаружил, что благодаря функции detach() класса QList, по неизвестному мне условию, всем объектам внутри контейнера выделяется новая область памяти, вследствие чего указатель начинает ссылаться на другой объект.
Условие внутри detach() выполняется, когда я вызываю функцию вида
Код:
computeFunc(GetFunc(myClassList));
int GetFunc(QList<MyClass> myClassList) { .. }
т.е. когда производится запуск конструктора копирования. И только в таком виде. Если поместить результат GetFunc в промежуточную переменную или передать myClassList по ссылке, проблем не возникает.
Вопрос: я неверно работаю с контейнером? Например, может положено хранить в листе только ссылки?
« Последнее редактирование: Апрель 03, 2015, 11:19 от GrieVeR-13 » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Апрель 03, 2015, 11:20 »

Передавай контейнер по константной ссылке. Зачем его копировать?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #2 : Апрель 03, 2015, 11:22 »

Фактически копирования не происходит до первого модифицирования контейнера
Цитировать
QList::​QList(const QList<T> & other)
Constructs a copy of other.

This operation takes constant time, because QList is implicitly shared. This makes returning a QList from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and that takes linear time.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Апрель 03, 2015, 11:24 »

Передавай контейнер по константной ссылке. Зачем его копировать?
Перераспределение может произойти и при простом добавлении элементов.

2 GrieVeR-13
Не храните в списке значения, храните указатели (желательно умные) на значения. Тогда, даже если список перераспределиться, указатели на значения останутся прежними.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #4 : Апрель 03, 2015, 11:40 »

Перераспределение может произойти и при простом добавлении элементов.

Почему так может произойти? Для std::list я видел схему из * next * prev. В qt механизм хитрее?
Записан
GrieVeR-13
Гость
« Ответ #5 : Апрель 03, 2015, 11:49 »

Old: даже при добавлении? Странно, что ранее никогда не сталкивался с таким явлением.
Тем не менее, все равно непонятно почему перераспределения не происходит, если не вкладывать GetFunc в computeFunc.
Код:
int i = GetFunc(myClassList);
computeFunc(i);
Хочу уточнить, что указатель ссылается на объект исходного контейнера, а не на его копию, если вдруг кто-то меня не так понял. Обновление памяти происходит при первом же обращении к функции operator[] после вызова computeFunc.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Апрель 03, 2015, 12:00 »

Почему так может произойти? Для std::list я видел схему из * next * prev. В qt механизм хитрее?

Табличка в начале вам поможет https://marcmutz.wordpress.com/effective-qt/containers/
Записан
qate
Супер
******
Offline Offline

Сообщений: 1176


Просмотр профиля
« Ответ #7 : Апрель 03, 2015, 12:14 »

В некоторый момент времени мне понадобилось хранить указатель на один из объектов в листе
Код:
MyClass *ptr = &myClassList[0]

храни индекс элемента, а не указатель
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Апрель 03, 2015, 12:54 »

Код:
computeFunc(GetFunc(myClassList));
int GetFunc(QList<MyClass> myClassList) { .. }
т.е. когда производится запуск конструктора копирования. И только в таком виде. Если поместить результат GetFunc в промежуточную переменную или передать myClassList по ссылке, проблем не возникает.
Вопрос: я неверно работаю с контейнером? Например, может положено хранить в листе только ссылки?
Ну Вы же передали копию - он Вам указатель на скопированный элемент и вернул. Все корректно с точки зрения языка. А когда он делал эту копию (сразу или после) - его личное дело. Зачем контейнер по значению передавать? Лень было писать const & - ну получайте проблемы. И QList здесь ни при чем - с любым контейнером то же самое
Записан
GrieVeR-13
Гость
« Ответ #9 : Апрель 03, 2015, 14:19 »

..Ну Вы же передали копию - он Вам указатель на скопированный элемент и вернул. Все корректно с точки зрения языка. А когда он делал эту копию (сразу или после) - его личное дело. Зачем контейнер по значению передавать? Лень было писать const & - ну получайте проблемы. И QList здесь ни при чем - с любым контейнером то же самое
Я чуть выше добавил, что указатель - на оригинал. Фокус именно в реализации контейнера (см. функцию detach()).
Константную ссылку написать забыл. Заинтересовала скорее возникшая проблема, чем метод решения. Всегда считал, что происходит разовая инициализация объекта в листе.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #10 : Апрель 03, 2015, 14:26 »

operator[] возвращает неконстантную ссылку на элемент контейнера, что подразумевает дальнейшую возможность его редактирования, что в свою очередь вызывает detach() для дублирования.
Записан
GrieVeR-13
Гость
« Ответ #11 : Апрель 03, 2015, 15:31 »

operator[] возвращает неконстантную ссылку на элемент контейнера, что подразумевает дальнейшую возможность его редактирования, что в свою очередь вызывает detach() для дублирования.
Да, именно такая ссылка мне и нужна, остается не ясным, с какой целью при определенных условиях дублировать весь список.
Всем большая благодарность за оперативные ответы.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Апрель 03, 2015, 16:36 »

...остается не ясным, с какой целью при определенных условиях дублировать весь список.
Так работает implicit sharing в Qt. Копирование происходит когда возникает необходимость.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #13 : Апрель 03, 2015, 20:20 »

GrieVeR-13, рекомендую почитать ПОЛНОСТЬЮ, документацию времён Qt4.6, на русском:
http://www.doc.crossplatform.ru/qt/4.6.x/containers.html

особо обратите внимание на раздел об итераторах, там много тонких мест указано, ну и разумеется раздел "Стратегии увеличения размера"
 
Записан

Юра.
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.061 секунд. Запросов: 22.