Russian Qt Forum

Qt => Общие вопросы => Тема начата: DarkHobbit от Октябрь 05, 2016, 06:42



Название: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: DarkHobbit от Октябрь 05, 2016, 06:42
Доброе утро.
Создал я свой класс, наследника QStringList. И понадобилось пробежаться по его элементам (не изменяя, только читая). Недолго думая, написал
Код:
foreach(const QString& s, myList)
Получил кучу ошибок. Странно, думаю, с самим QStringList проблем никогда не было.
Наткнувшись на сообщение об отсутствии копирующего конструктора, понял, что макрос пытается сделать копию объекта.  Даже пытается синтезировать этот копирующий конструктор, но спотыкается об объект класса QSettings, который является был :) одним из полей моего класса, а у QSettings копирующий конструктор приватный.
Перечитал справку. Действительно:
Цитировать
Qt automatically takes a copy of the container when it enters a foreach loop
Ниже, правда, в утешение говорится:
Цитировать
(If you do not modify the container, the copy still takes place, but thanks to implicit sharing copying a container is very fast.)
Почитав бегло главу про этот самый implicit sharing copying, я понял, что разработчики Qt добивались его специально, и даже приводится список классов, в которых оно поддерживается.

От QSettings в полях я избавился (он там был нужен только для пары методов, и я его перенёс), и программа собралась. Но осадочек в голове остался.

Собственно, вопрос: а вообще-то, в моём классе будет работать быстрое копирование, или будет делаться deep copy, а я об этом никогда не узнаю? Может, быстрее и надёжнее будет обычный, хотя и топорный for по элементам списка? Или можно выполнить какие-то условия, чтобы в моём классе-наследнике быстрое копирование тоже работало, и если да, то какие?

Версии Qt, под которыми собирается мой проект - от 4.6.0 до 5.6.1.


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: ssoft от Октябрь 05, 2016, 08:24
Собственно, вопрос: а вообще-то, в моём классе будет работать быстрое копированиеПо скорости , или будет делаться deep copy, а я об этом никогда не узнаю?

Сначала про копирование.  Реализация implicit shared сущностей  подразумевает копирование только в момент вызова не константных методов. Если их вызов не предвидится, то уже у нового QStringList данные всегда будут неявно разделены с исходным.

Может, быстрее и надёжнее будет обычный, хотя и топорный for по элементам списка?

Надежнее будет та реализация, которая более понятна, foreach введен для удобства. По скорости реализация Qt уступала обычному for примерно 25-50%, в то время как реализация boost не уступала совсем (я проводил бенчмарки на Qt 4.7.4). А вообще пора переходить на новый стандарт языка ;D

Код
C++ (Qt)
for( QString string : string_list)

Или можно выполнить какие-то условия, чтобы в моём классе-наследнике быстрое копирование тоже работало, и если да, то какие?

Независимого механизма implicit shared в Qt не предложено. Возможно наследование своих структур от QSharedData и использование QSharedDataPointer.


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: Авварон от Октябрь 05, 2016, 08:44

Код
C++ (Qt)
for( QString string : string_list)


Код
C++ (Qt)
for( const auto &string : qAsConst(string_list))


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: Igors от Октябрь 05, 2016, 08:59
Может, быстрее и надёжнее будет обычный, хотя и топорный for по элементам списка?
Интересно наблюдать как эти остатки здравого смысла будут безжалостно задавлены :) Копирующий конструктор, имплисит шара, новый стандарт, и, наконец, последний писк моды qAsConst. И чему же все это посвящено? Избежать for - он уже "топорный". А почему? Ну могут подумать что, мол, мало знаю, "не владею" и все такое...

Вы бы голову-то пожалели, жалко тратить ее на такую фигню как форыч


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: ssoft от Октябрь 05, 2016, 09:46
Интересен foreach, как и auto, становится тогда, когда обычная запись "замусоривает" восприятие кода (особенно, если используется мета программирование на шаблонах)

Например, простейший код

Код
C++ (Qt)
std::unordered_map< Key, Value > container;
...
for ( std::unordered_map< Key, Value >::iterator iter iter = container.begin();
   iter != container.end(); ++iter )
{
   ...
}
 

может быть реализован так


Код
C++ (Qt)
typedef std::unordered_map< Key, Value > Container;
Container container;
...
typedef Container::iterator Iterator;
for ( Iterator iter = container.begin();
   iter != container.end(); ++iter )
{
   ...
}
 

а может  так

Код
C++ (Qt)
using Container = std::unordered_map< Key, Value >;
Container container;
...
for ( auto & pair : container )
{
   ...
}
 

что просто облегчает чтение и позволяет сфокусироваться на сути. А так дело привычки  ;)


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: Igors от Октябрь 05, 2016, 09:50
что просто облегчает чтение и позволяет сфокусироваться на сути. А так дело привычки  ;)
Согласен конечно, но все хорошо в меру  :)


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: qate от Октябрь 05, 2016, 09:58
Код
C++ (Qt)
for( const auto &string : qAsConst(string_list))

а разве просто
Код
C++ (Qt)
for (auto s: somestringlist)

будет не достаточно ?
тип s должен быть QString const&


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: Авварон от Октябрь 05, 2016, 11:49

а разве просто
Код
C++ (Qt)
for (auto s: somestringlist)

будет не достаточно ?
тип s должен быть QString const&


Нет, с++11 for вызывает неконстантные begin/end, а они вызовут детач контейнера.
UPD: нет, тип auto будет QString

Интересно наблюдать как эти остатки здравого смысла будут безжалостно задавлены :) Копирующий конструктор, имплисит шара, новый стандарт, и, наконец, последний писк моды qAsConst. И чему же все это посвящено? Избежать for - он уже "топорный". А почему? Ну могут подумать что, мол, мало знаю, "не владею" и все такое...

Вы бы голову-то пожалели, жалко тратить ее на такую фигню как форыч

Да, имплисит шару в контейнерах надо закопать, но не поэтому, а потому что с ними невозможен мув объекта внутрь контейнера (QVector<std::unique_ptr> сделать нельзя)


Название: Re: Насколько тяжёл будет foreach по наследнику QStringList
Отправлено: DarkHobbit от Октябрь 06, 2016, 22:04
Всем спасибо за ответы.
Пожалуй да, в сомнительных случаях стоит использовать обычный for.
Половина ответов сводится к рекомендации задействовать for из C++11. Я этот вариант обдумываю, я понимаю, что рано или поздно на него перейду, но пока не готов отказаться от совместимости со старым стандартом, ибо есть экзотические, но интересные для меня платформы, на которые в 2016 году всё ещё не завезли C++11.