Russian Qt Forum

Qt => Общие вопросы => Тема начата: usr00210 от Август 30, 2010, 05:15



Название: Безопасен ли такой код QList<QPushButton*>?
Отправлено: usr00210 от Август 30, 2010, 05:15
Код:
int main( int argc, char *argv[] )
{
    QApplication AppInstance( argc, argv );
    QList<QPushButton*> qPButtonList;

    ...

    AppInstance.exec();

    foreach( QPushButton* pButton, qPButtonList ) // Безопасен ли и вообще правилен ли такой код?
        delete pButton;

    return 0;
}


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 06:19
Сам контейнер не очищается. Используй лучше.
Код
C++ (Qt)
qDeleteAll (qPButtonList);
qPButtonList.clear ();
 


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 08:09
КуТ делает копию контейнера при входе в фоич. Следовательно список, который в фоич, будет содержать те же указатели что и список выше. А затем происходит удаление памяти по этим указателям, выходит, что список уже будет содержать не валидные указатели, что уже плохо, даже если отсутствует другой код.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: usr00210 от Август 30, 2010, 09:11
Спасибо!


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 13:47
КуТ делает копию контейнера при входе в фоич. Следовательно список, который в фоич, будет содержать те же указатели что и список выше.
Будет, но контейнер не копируется, просто применяется константный итератор


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 14:09
Что-то Шлее заврался.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 14:33
Что-то Шлее заврался.
Не заврался. С точки зрения C++ контейнер будет копироваться во временный объект, но с точки зрения Qt, самого копирования данных не произойдет, временному контейнеру будет присвоен указатель на управляющую структуру контейнера и увеличен счетчик использования. При разрушении временного объекта этот счетчик просто уменьшиться.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: usr00210 от Август 30, 2010, 14:53
Что-то Шлее заврался.
Не заврался. С точки зрения C++ контейнер будет копироваться во временный объект, но с точки зрения Qt, самого копирования данных не произойдет, временному контейнеру будет присвоен указатель на управляющую структуру контейнера и увеличен счетчик использования. При разрушении временного объекта этот счетчик просто уменьшиться.

в документации Qt для этого есть специальная терминология deep copy - когда фактически создается дубликать и еще какое-то копирование (термин забыл), когда возвращается указатель и увеличивается счетчик объектов.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 14:54
в документации Qt для этого есть специальная терминология deep copy - когда фактически создается дубликать и еще какое-то копирование (термин забыл), когда возвращается указатель и увеличивается счетчик объектов.
Implicit Sharing


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: usr00210 от Август 30, 2010, 14:57
в документации Qt для этого есть специальная терминология deep copy - когда фактически создается дубликать и еще какое-то копирование (термин забыл), когда возвращается указатель и увеличивается счетчик объектов.
Implicit Sharing

нет, этот термин они используют для спец классов оберток, а тут речь идет именно о механизме копирования shallow copy (нашел!)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 15:02
Не мешало бы добавить в документацию что foreach для "не Qt" контейнера (напр std::vector) может окончиться печально


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 15:04
нет, этот термин они используют для спец классов оберток, а тут речь идет именно о механизме копирования shallow copy (нашел!)
Implicit Sharing - это название самой технологии.
В assistant есть отдельная глава, посвященная ей.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: usr00210 от Август 30, 2010, 15:09
Не мешало бы добавить в документацию что foreach для "не Qt" контейнера (напр std::vector) может окончиться печально

а там вроде бы написано, что безопасно можно использовать только Qt контейнеры. вроде бы  ;D


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 15:17
Мало верится, что константный итератор реализуется копированием контейнера, т.к обычно операции чтения, для которых он и применяется, выполняются быстрее записи, а так выходит наоборот будет. Ведь использование константного итератора нужно, чтобы отлавливать ошибки при попытки модификации "не модифицируемых" данных на этапе компиляции и не более.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 15:22
Мало верится, что константный итератор реализуется копированием контейнера...
Эээ. Как понять "константный итератор реализуется копированием контейнера"?


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 15:23
Будет, но контейнер не копируется, просто применяется константный итератор
С точки зрения C++ контейнер будет копироваться во временный объект

???


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 15:34
Код
C++ (Qt)
template <typename T>
class QForeachContainer {
public:
   inline QForeachContainer(const T& t) : c(t), brk(0), i(c.begin()), e(c.end()) { } // <<<<<< При создании объекта QForeachContainer контейнер копируется
   const T c; // <<<<<< в константный объект c
   int brk;
   typename T::const_iterator i, e;
};
 
#define Q_FOREACH(variable, container)                                \
for (QForeachContainer<__typeof__(container)> _container_(container); \
    !_container_.brk && _container_.i != _container_.e;              \
    __extension__  ({ ++_container_.brk; ++_container_.i; }))                       \
   for (variable = *_container_.i;; __extension__ ({--_container_.brk; break;}))
 
С точки зрения C++ контейнер копируется во временный объект. Но если вспомнить, что все контейнеры Qt реализуют Implicit Sharing, то понимаем, что копировании самих данных контейнера не происходит.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 15:36
Так понятно, константность итератора тут по-сути не причем.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 15:59
Так понятно, константность итератора тут по-сути не причем.
Если бы он не был константным (и было бы "Т с" без const) то данные контейнера бы реально копировались


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 16:32
Точно? Потому что Шлее в конце 4 главы приводит пример, в котором он говорит, что копирование происходит только при первой попытки модификации данных.

Код:
QString str1; //refers to the shared_null
QString str2; //refers to the shared_null

str1 = "new string";
str2 = str1; // str1 and str2 refer to the same data

str1 += "add new data"; // is occuring data copy for str1


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 16:58
Точно? Потому что Шлее в конце 4 главы приводит пример, в котором он говорит, что копирование происходит только при первой попытки модификации данных.
Копирование "чего". Пусть неконстантный итератор возвращает ссылку на элемент контейнера. Значит вся структура контейнера должна быть "честно" скопирована, выделена память под все элементы (согласно sizeof элемента). При этом сами элементы могут копироваться как "shallow" - если они в стиле Qt и умеют это делать.

Мой (субъективный) совет не увлекаться "модерном" а действовать по классике C/C++, просто и надежно. Напр ну сдался Вам тот foreach? Сэкономили 1-2 строчки а при случае огребли по полной. Qt свои приемчики предлагает но не навязывает, можно писать и так:

Код
C++ (Qt)
size_t i, limit = myList.size();
for (i = 0; i < limit; ++i)
 if (myList[i])..
 


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 17:06
Сэкономили 1-2 строчки а при случае огребли по полной. Qt свои приемчики предлагает но не навязывает, можно писать и так:

Код
C++ (Qt)
size_t i, limit = myList.size();
for (i = 0; i < limit; ++i)
 if (myList[i])..
 
Не, так точно не стоит. Лучше через Q*Iterator.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 17:10
Не, так точно не стоит. Лучше через Q*Iterator.
Да отчего же? Боитесь расходов на оператор []? Они пренебрежимо малы даже по сравнению с shallow  :)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 17:14
Да отчего же? Боитесь расходов на оператор []? Они пренебрежимо малы даже по сравнению с shallow  :)
А как соотносятся итераторы и shallow?
Чем же так опасны итераторы?


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 17:27
А как соотносятся итераторы и shallow?
Чем же так опасны итераторы?
Ничем не опасны  :) Просто цикл for проще, короче и индекс элемента всегда под рукой


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 17:32
for (QList <int>::iterator......
Чем тебе этот for не угодил?


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 17:33
Ничем не опасны  :) Просто цикл for проще, короче и индекс элемента всегда под рукой
Чем проще? А если индекс элемента не нужен вообще? Для чего инкрементировать/декрименторовать не нужную переменную, да еще постоянно вычислять по ней смещение до нужного элемента? А как быть с индексом при работе со связанным списком (его конечно можно приспособить, только нужно ли?).


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 17:33
ИМХО разработчиками не нужно было документировать как вообще происходит распределения  памяти.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 17:35
Кстати, Александреску не рекомендует засовывать в контейнеры ссылки.
Это так, к слову. :)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 17:36
ИМХО разработчиками не нужно было документировать как вообще происходит распределения  памяти.
Почему?


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 17:37
BRE, чтобы таких холиваров не раздувалось. ;)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 17:42
ИМХО разработчиками не нужно было документировать как вообще происходит распределения  памяти.
Почему?

Не было бы таких вопросов. Ведь это реализация, а она не так уж важна.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Sancho_s_rancho от Август 30, 2010, 17:44
foreach - богомерзкий прием, богомерзкого С с шаблонами.

http://labs.trolltech.com/blogs/2009/01/23/iterating-efficiently/


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 17:45
Не было бы таких вопросов. Ведь это реализация, а она не так уж важна.
IMHO, чем больше ты будешь знать как "это" работает, тем более эффективно ты сможешь "это" использовать.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 17:46
foreach - богомерзкий прием, богомерзкого С с шаблонами.
Ну, для использования итераторов не обязательно использовать foreach.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 17:47
Не давно осилил очередную книгу Рихтера по вынь-апи . Так вот в винде такое распределения памяти, что если юзать все возможности, то можно офигеть. Поэтому в большинстве случаев, если MFC, то используют new, а как оно там дальше мне по барабану, будет ли та память в страничный файл выгружена, какое там смещение или защита страницы. Вижу в этом аналогию.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Sancho_s_rancho от Август 30, 2010, 17:48
foreach - богомерзкий прием, богомерзкого С с шаблонами.
Ну, для использования итераторов не обязательно использовать foreach.

Да я не серьезно. Просто потроллить после рабочего дня захотелось.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 17:53
А вообще хорошо, чтобы этот механизм каким-то образом был в стандарт с++ запихнутым , тогда точно вопросов не будет.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 18:13
for (QList <int>::iterator......
Чем тебе этот for не угодил?
Тем что строка длинная получается. и все это смахивает на "демонстрацию познаний" взамен содержательной работы  :)

Чем проще? А если индекс элемента не нужен вообще? Для чего инкрементировать/декрименторовать не нужную переменную, да еще постоянно вычислять по ней смещение до нужного элемента? А как быть с индексом при работе со связанным списком (его конечно можно приспособить, только нужно ли?).
Разговор о контейнерах с прямым доступом, для остальных (хочешь - не хочешь) итератор использовать придется. "Смещение до нужного элемента" по существу та же адресная арифметика, плюс небольшие накладные расходы. Утверждение что ++ итератора якобы "ощутимо быстрее" взятия по индексу лишено оснований. Это обойдется в 2-3 машинных команды даже для классического vector, что пренебрежимо мало по сравнению с тем что делается в теле цикла.  Для остальных контейнеров вообще дело темное кто там быстрее. Так что дело вкуса что использовать - итератор или индекс.

Если речь идет о скорости - с удовольствием приму участие в обсуждении. Только по-честному. А то Вы спокойно относитесь к тому что контейнер перераспределяет память (что стоит сотен/тысяч команд), входит в EnterCriticalSection при добавлении нового элемента (напр std::set) и.т.п. В этом контексте говорить о "выжимании микронов" неуместно  :)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 18:18
Индексный - сишный подход. В с++ принято итераторами пользоваться.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 18:19
А то Вы спокойно относитесь к тому что контейнер перераспределяет память (что стоит сотен/тысяч команд)...
Если это обращение ко мне, то мне не понятно почему я спокойно к этому отношусь?  :)
А точнее мне не понятно какое перераспределение памяти имеется ввиду.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Alex_cs_gsp от Август 30, 2010, 18:33
Отнюдь не всегда перераспределение памяти стоит сотни тысяч команд. Например в винде, выделить блок памяти менее размера одной страницы попросту нельзя, а это 2 или 4 кб, тем не менее, каким то чудом new может вернуть память в один байт.  Поэтому все зависит от диспетчеризации. Никто вам не мешает зарезервировать нужное количество памяти.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 18:36
Индексный - сишный подход. В с++ принято итераторами пользоваться.
Ну так С++ всего лишь (небольшая) надстройка над базовым С. Так, флигелек в котором живет "наша малышь"  :)

Если это обращение ко мне, то мне не понятно почему я спокойно к этому отношусь?  :)
А точнее мне не понятно какое перераспределение памяти имеется ввиду.
Никаких "персональных выпадов" (по крайней мере с моей стороны  :) ). Просто если речь об эффективности контейнеров, надо говорить/обсуждать применяемые ими "стратегии" (мерзкое слово) распределения памяти/ресурсов, т.к. 95% эффективности определяется этим. Остальные 5% останутся пятью, как бы мы ни старались  :) Любой контейнер есть "растущий массив" и все зависит от того как он растет.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Пантер от Август 30, 2010, 18:43
Ну так С++ всего лишь (небольшая) надстройка над базовым С. Так, флигелек в котором живет "наша малышь"  :)
"А мужики-то не знают..."


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 19:00
Ну так С++ всего лишь (небольшая) надстройка над базовым С. Так, флигелек в котором живет "наша малышь"  :)
Это совершенно не так.
C - это процедурный язык, C++ - объектно-ориентированный.
Между двумя этими подходами огромная разница, начиная от проектировании и заканчивая реализацией задачи. Там все по другому, и кто только не пытался это донести до пользователей, начиная с автора языка.  :)
А то что синтаксис их похож... ну так исторически сложилось, Страуструп выбрал его.

Просто если речь об эффективности контейнеров, надо говорить/обсуждать применяемые ими "стратегии" (мерзкое слово) распределения памяти/ресурсов, т.к. 95% эффективности определяется этим. Остальные 5% останутся пятью, как бы мы ни старались  :) Любой контейнер есть "растущий массив" и все зависит от того как он растет.
А какое отношение имеет стратегия распределения памяти к методам доступа. Начали с индексов/итераторов, закончили стратегией распределения.  :)
В принципе можно обсудить и распределение памяти.


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 19:20
Это совершенно не так.
C - это процедурный язык, C++ - объектно-ориентированный.
Между двумя этими подходами огромная разница,
Да принципиально никакой. В любом случае надо выделить части/модули, организовать их взаимодействие по-умному и.т.д. На ++ это удобнее но суть та же.

А какое отношение имеет стратегия распределения памяти к методам доступа. Начали с индексов/итераторов, закончили стратегией распределения.  :)
На "методах доступа" много не выжать, как ни старайтесь. Эффективность того же вектора определяется тем как часто он бросается все перераспределять (туча конструкторов копирования) и с др. стороны не много ли он жрет памяти "про запас" чтобы избежать постоянных перераспределений


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 19:36
Да принципиально никакой. В любом случае надо выделить части/модули, организовать их взаимодействие по-умному и.т.д. На ++ это удобнее но суть та же.
Дааа, достаточно емкое определение....
А одни люди научные труды/толстенные книги пишут... растолковать/донести до других людей хотят.... а тут смотри как все просто... "по-умному" главное... А по умному это как?  :)

На "методах доступа" много не выжать, как ни старайтесь. Эффективность того же вектора определяется тем как часто он бросается все перераспределять (туча конструкторов копирования) и с др. стороны не много ли он жрет памяти "про запас" чтобы избежать постоянных перераспределений
Чего не выжать?  :)
Все... есть контейнер... он уже есть, перераспределять его не надо.... Вот до этого мы обсуждали как нам по нему пройтись.  :)



Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: Igors от Август 30, 2010, 19:44
А одни люди научные труды/толстенные книги пишут... растолковать/донести до других людей хотят....
Кто умеет - делает. Кто не умеет - учит как надо делать. Кто не умеет учить... и.т.д

а тут смотри как все просто... "по-умному" главное... А по умному это как?  :)
А я и не говорил что это просто. Наоборот - это очень сложно

Все... есть контейнер... он уже есть, перераспределять его не надо.... Вот до этого мы обсуждали как нам по нему пройтись.  :)
Да как угодно - здесь-то проблем нет, и считать затраты "глуповасто"  :)


Название: Re: Безопасен ли такой код QList<QPushButton*>?
Отправлено: BRE от Август 30, 2010, 19:53
Кто умеет - делает.
К сожалению так бывает далеко не всегда. :)