Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Сентябрь 25, 2009, 15:12



Название: QList + qSort
Отправлено: Igors от Сентябрь 25, 2009, 15:12
Добрый день

Код:
#include <qDebug>

#define  NUM_TEST 1024

struct CTest {
CTest( double x ) : mX(x) {}
   ~CTest( void ) { qDebug() << "destruct " << mX; }

bool operator < ( const CTest & t ) const { return mX < t.mX; }

// data
double mX;
QString mDummy;
};

int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
QList <CTest> theList;

for (int i = 0; i < NUM_TEST; ++i)
theList.append(CTest(double(qrand()) / RAND_MAX));

qSort(theList.begin(), theList.end());

return 0;
}
Консоль печатает вызовы ~CTest.
Вопрос: почему и хорошо/правильно ли это для QList? Ведь QList хранит указатели на данные и было бы очень к месту сортировать указатели не вызывая тонны конструкторов/деструкторов.


Название: Re: QList + qSort
Отправлено: BlackTass от Сентябрь 25, 2009, 15:14
как мне кажется вызовы деструктора идут после ретурна, то есть когда удаляются локальные переменные. Попробуйте поставить куДебаг перед ретурном и посмотреть до или после будут вызовы деструкторов


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 25, 2009, 15:26
как мне кажется вызовы деструктора идут после ретурна, то есть когда удаляются локальные переменные. Попробуйте поставить куДебаг перед ретурном и посмотреть до или после будут вызовы деструкторов
Правильное замечание в том смысле что тест должен быть чище. Испраляюсь

Код:
#include <qDebug>

#define  NUM_TEST  8

struct CTest {
     CTest( double x ) : mX(x) {}
   ~CTest( void ) { qDebug() << "destruct " << mX; }

     bool operator < ( const CTest & t ) const { return mX < t.mX; }
     
// data
     double mX;
     QString mDummy;
};

int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
QList <CTest> theList;
qDebug() << "\nAppending";

for (int i = 0; i < NUM_TEST; ++i)
theList.append(CTest(double(qrand()) / RAND_MAX));

qDebug() << "\nSorting";

qSort(theList.begin(), theList.end());
// qSort(theList);
qDebug() << "\nEnd";

return 0;
}

Консоль
Цитировать
Appending
destruct  7.82637e-06
destruct  0.131538
destruct  0.755605
destruct  0.45865
destruct  0.532767
destruct  0.218959
destruct  0.0470446
destruct  0.678865

Sorting
destruct  0.532767
destruct  0.755605
destruct  0.678865
destruct  0.532767
destruct  0.0470446
destruct  0.0470446
destruct  0.131538
destruct  0.218959
destruct  0.678865

End
destruct  0.755605
destruct  0.678865
destruct  0.532767
destruct  0.45865
destruct  0.218959
destruct  0.131538
destruct  0.0470446
destruct  7.82637e-06


Название: Re: QList + qSort
Отправлено: Winstrol от Сентябрь 25, 2009, 15:36
Вопрос: почему и хорошо/правильно ли это для QList? Ведь QList хранит указатели на данные и было бы очень к месту сортировать указатели не вызывая тонны конструкторов/деструкторов.
Видимо, потому, что qSort ничего не известно о внутренностях QList.


Название: Re: QList + qSort
Отправлено: BRE от Сентябрь 25, 2009, 15:52
qSort во всю использует qSwap, который создает временный объект T. Вот для разрушения временных объектов и вызывается деструктор.


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 25, 2009, 15:56
Видимо, потому, что qSort ничего не известно о внутренностях QList.
Тогда уж надо предоставить пользователю метод QList::sort и написать в букваре что он может быть значительно быстрее чем qSort. А пока я вижу что

QList <MyObject *> может быть во много раз быстрее (для хороших объектов) чем QList <MyObject>


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 25, 2009, 16:09
qSort во всю использует qSwap, который создает временный объект T. Вот для разрушения временных объектов и вызывается деструктор.
То да, но для QList это сделано не по уму. Если уж мы тратим драгоценные 4/8 байт для указателя на объект - чего мы тогда сам объект дергаем/перемещаем?


Название: Re: QList + qSort
Отправлено: BRE от Сентябрь 25, 2009, 16:30
То да, но для QList это сделано не по уму. Если уж мы тратим драгоценные 4/8 байт для указателя на объект - чего мы тогда сам объект дергаем/перемещаем?
Как писал выше Winstrol, qSort (как и qSwap и другие алгоритмы) сделан универсальным, ему не важен тип контейнер, он не знает его внутреннее устройство.
На счет функций sort оптимизированных для каждого контейнера.... По моему, для написания GUI qSort работает достаточно быстро, а большего Qt и не должна предоставлять. IMHO, не нужно от нее требовать всего.  :)


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 25, 2009, 17:18
Да как будто аккуратная сортировка есть "слишком много чтобы просить" :)
Заметим, кстати, что QList::swap имеется и переставляет указатели, а не объекты.


Название: Re: QList + qSort
Отправлено: ритт от Сентябрь 28, 2009, 11:13
хрен пойму почему в данном случае не использовать QList <CTest*> ?

а что при "Appending" вызывается полный набор деструкторов, это нормально, да?:)


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 11:40
хороший вопрос и отличная возможность показать себя и вписать свое имя в историю - ждем патчей реализующий специализацию template<typename Container> void qSort(Container &container) для QList. Кто возьмется?


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 11:43
хрен пойму почему в данном случае не использовать QList <CTest*> ?

а что при "Appending" вызывается полный набор деструкторов, это нормально, да?:)
кстати хороший вопрос откуда они берутся. Скорее всего из-за создание временного объекта на стеке и в релизной сборке этих деструкторов вероятно не будет...


Название: Re: QList + qSort
Отправлено: BRE от Сентябрь 28, 2009, 12:08
кстати хороший вопрос откуда они берутся. Скорее всего из-за создание временного объекта на стеке и в релизной сборке этих деструкторов вероятно не будет...
Как это не будет - будет.
Вот здесь создается временный объект:
Код
C++ (Qt)
               theList.append( CTest(double(qrand()) / RAND_MAX));
 


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 28, 2009, 12:12
хрен пойму почему в данном случае не использовать QList <CTest*> ?
Потому что qSort требует оператор < а для <CTest*> он будет сравнивать указатели - т.е. делать совсем не то что нужно
а что при "Appending" вызывается полный набор деструкторов, это нормально, да?:)
Это "неизбежное зло" любого контейнера - данные должны быть сначала скопированы "в нутро".
Правда здесь с ихним "shallow copy" это не так болезненно как в STL.

Цитировать
кстати хороший вопрос откуда они берутся. Скорее всего из-за создание временного объекта на стеке и в релизной сборке этих деструкторов вероятно не будет...
будет, деструктор для временного CTest должен вызываться по окончании theList.append


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 28, 2009, 12:21
хороший вопрос и отличная возможность показать себя и вписать свое имя в историю - ждем патчей реализующий специализацию template<typename Container> void qSort(Container &container) для QList. Кто возьмется?
Никто кроме Qt, потому что все глухо "private" (обратная сторона медали). Этот feature request я им уже написал


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 12:22
хрен пойму почему в данном случае не использовать QList <CTest*> ?
Потому что qSort требует оператор < а для <CTest*> он будет сравнивать указатели - т.е. делать совсем не то что нужно
можно определить свой функтор для сравнения (последний аргумент qLess , либо глобальный operator<(CTest*, CTest*)

Цитировать
кстати хороший вопрос откуда они берутся. Скорее всего из-за создание временного объекта на стеке и в релизной сборке этих деструкторов вероятно не будет...
будет, деструктор для временного CTest должен вызываться по окончании theList.append
не обязательно - по стандарту в данном случае т.к. функция принимает константную ссылку и пользователь передает временный объект, компилятор имеет право продлить жизнь и не создавать еще одну копию.


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 12:24
хороший вопрос и отличная возможность показать себя и вписать свое имя в историю - ждем патчей реализующий специализацию template<typename Container> void qSort(Container &container) для QList. Кто возьмется?
Никто кроме Qt, потому что все глухо "private" (обратная сторона медали). Этот feature request я им уже написал
Qt разрабатывается открыто (http://qt.gitorious.org/qt/qt) и легко принимается (http://qt.gitorious.org/qt/pages/QtContributionGuidelines) сторонний код.


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 28, 2009, 12:56
можно определить свой функтор для сравнения (последний аргумент qLess , либо глобальный operator<(CTest*, CTest*)
Ну такой глобальный оператор определять стремно и не хочется. А про функтор и qLess покажите как это делается если есть возможность (просто интересно).

Конечно, если нужно сортировать быстрее, выкрутиться можно, например так

Код:
QVector <CTest *> theVec;
...
// заполняем вектор
theVec.push_back(new CTest());
...
qsort(&theVec[0], theVec.size(), sizeof(CTest *), CompTestPtr);   

И это наверняка не один способ. Но по-моему главное в контейнерах это УДОБСТВО их использования, а здесь этого нет. Так что пусть пишут QList::sort  :)


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 13:04
можно определить свой функтор для сравнения (последний аргумент qLess , либо глобальный operator<(CTest*, CTest*)
Ну такой глобальный оператор определять стремно и не хочется. А про функтор и qLess покажите как это делается если есть возможность (просто интересно).
Это есть в документации: http://doc.qt.nokia.com/4.5/qtalgorithms.html#qSort-2

Конечно, если нужно сортировать быстрее, выкрутиться можно, например так

Код:
QVector <CTest *> theVec;
...
// заполняем вектор
theVec.push_back(new CTest());
...
qsort(&theVec[0], theVec.size(), sizeof(CTest *), CompTestPtr);  
это совершенно не быстрее. Перемещение элементов в QVector всегда будет медленнее - см описание сложностей алгоритмов над разными контейнерами - http://doc.qt.nokia.com/4.5/containers.html#algorithmic-complexity
ах, не заметил что в данном случае операция идет не над вектором а над линейным блоком памяти.
И это наверняка не один способ. Но по-моему главное в контейнерах это УДОБСТВО их использования, а здесь этого нет. Так что пусть пишут QList::sort  :)
"пусть пишут" это неконструктивно :)
О чем я говорю - вы можете сделать Qt лучше, написав патч для Qt реализующий специализацию qSort для контейнера QList и послав патч разработчикам Qt, сделав доброе дело для всех пользоваталей библиотеки и запечатлев свое имя в истории (имя автора патча будет видно всем в истории коммитов (http://qt.gitorious.org/qt/qt) Qt).


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 28, 2009, 14:09
Это есть в документации: http://doc.qt.nokia.com/4.5/qtalgorithms.html#qSort-2
Ага, спасибо, этот путь короче для QList<CTest *>
"пусть пишут" это неконструктивно :)
Вообще говоря - неконструктивно. Но в данном конкретном случае дописать этот метод для QList - дело 5 минут и текст моего патча был бы ни к чему. Просто я не могу сделать это сам из-за private, пришлось подарить им идею  :)


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 15:13
Это есть в документации: http://doc.qt.nokia.com/4.5/qtalgorithms.html#qSort-2
Ага, спасибо, этот путь короче для QList<CTest *>
"пусть пишут" это неконструктивно :)
Вообще говоря - неконструктивно. Но в данном конкретном случае дописать этот метод для QList - дело 5 минут и текст моего патча был бы ни к чему. Просто я не могу сделать это сам из-за private, пришлось подарить им идею  :)
лучше дарить идеи оформленные в виде патча :) согласен что патч не сложный, но реализовать его в виде метода QList::sort некорректно - т.к. потребуется изменять уже существующие приложния чтобы получить преимущество от этой новой фичи. вместо этого правильный подход был бы сделать специализацию шаблона qSort для QList (причем две специализации - для случае когда передается контейнер и когда передается часть контейнера через итераторы). Плюс надо написать юнит-тесты. Вся эта работа несложная, но не на 5 минут.

ждем вашего патча ;)


Название: Re: QList + qSort
Отправлено: Igors от Сентябрь 28, 2009, 15:53
лучше дарить идеи оформленные в виде патча :) согласен что патч не сложный, но реализовать его в виде метода QList::sort некорректно - т.к. потребуется изменять уже существующие приложния чтобы получить преимущество от этой новой фичи. вместо этого правильный подход был бы сделать специализацию шаблона qSort для QList (причем две специализации - для случае когда передается контейнер и когда передается часть контейнера через итераторы). Плюс надо написать юнит-тесты. Вся эта работа несложная, но не на 5 минут.

ждем вашего патча ;)
"Инициатива наказуема исполнением" :)  Но я с Вами не согласен по всем позициям:

1) То, что QList мог бы сортировать быстрее = глухая специфика/свойство QList который держит массив указателей, для других контейнеров это смысла не имеет. Поэтому нужен метод QList::sort, а не  специализация шаблона для одного класса.

2) Изменять функциональность существующих/работающих программ (пусть даже из благих побуждений) всегда чревато неприятными последствиями. Результаты 2 сортировок НЕ равны, например кто-то мог рассчитывать что объекты будут перемещены. Поэтому qSort надо оставить как есть.

3) Хорошо (удобно для разработчика) поставленная задача весит гораздо больше чем масса примеров и кода. QList::sort сделать очень просто а результат был бы налицо, легко понятен и документируем.

Ну и вообще, я к славе не стремлюсь  :)


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 16:25
"Инициатива наказуема исполнением" :)  Но я с Вами не согласен по всем позициям:

1) То, что QList мог бы сортировать быстрее = глухая специфика/свойство QList который держит массив указателей, для других контейнеров это смысла не имеет. Поэтому нужен метод QList::sort, а не  специализация шаблона для одного класса.
сорри, но логики здесь не вижу - есть единый интерфейс для сортировки любых отрезков(range)/контейнеров, и пользователю этого api совершенно не нужно знать что в некоторых случаях для конкретного типа контейнера используется более оптимальный алгоритм.

2) Изменять функциональность существующих/работающих программ (пусть даже из благих побуждений) всегда чревато неприятными последствиями. Результаты 2 сортировок НЕ равны, например кто-то мог рассчитывать что объекты будут перемещены. Поэтому qSort надо оставить как есть.

элементы _будут_ перемещены, просто не будет дополнительных временных объектов. Имхо если пользователь рассчитывает на определенное количество вызовов конструкторов/деструкторов - он сам ищет себе проблемы.

3) Хорошо (удобно для разработчика) поставленная задача весит гораздо больше чем масса примеров и кода. QList::sort сделать очень просто а результат был бы налицо, легко понятен и документируем.

Ну и вообще, я к славе не стремлюсь  :)

ок :) я себе записал эту проблемку в список задачек над которыми надо подумать, надеюсь в 4.7 реализую.


Название: Re: QList + qSort
Отправлено: ритт от Сентябрь 28, 2009, 18:35
Qt разрабатывается открыто (http://qt.gitorious.org/qt/qt) и легко принимается (http://qt.gitorious.org/qt/pages/QtContributionGuidelines) сторонний код.
угу, легко. но порой доо..оолго :)


Название: Re: QList + qSort
Отправлено: shadone от Сентябрь 28, 2009, 18:41
Qt разрабатывается открыто (http://qt.gitorious.org/qt/qt) и легко принимается (http://qt.gitorious.org/qt/pages/QtContributionGuidelines) сторонний код.
угу, легко. но порой доо..оолго :)
;) ну ты я думаю знаешь причины - обязательное сканирование кода (полу-)автоматизированной системой на предмет патентных ограничений, ручной ревью кода и общая загруженность разработчиков...


Название: Re: QList + qSort
Отправлено: udovolstvie от Март 01, 2010, 15:03
Здравствуйте.
У меня похожая проблема,
может быть знаете её решение.
Описан класс V1, в нем определен оператор
bool operator<(const V1&rh){if (this==&rh) return false;else if (x<rh.x && y<rh.y && z<rh.z) return true; else return false;}

пытаюсь скомпилировать, ругается:
Error   2   error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const Core2::V1' (or there is no acceptable conversion)   C:\Qt\4.6.0\include\QtCore\qalgorithms.h   161   RFCore

что не так?

upd:====
надо было
bool operator<(const V1&rh) const {if (this==&rh) return false;else if (x<rh.x && y<rh.y && z<rh.z) return true; else return false;}


Название: Re: QList + qSort
Отправлено: shadone от Март 01, 2010, 15:10
const?


Название: Re: QList + qSort
Отправлено: BigZ от Март 02, 2010, 09:55
Qt разрабатывается открыто (http://qt.gitorious.org/qt/qt) и легко принимается (http://qt.gitorious.org/qt/pages/QtContributionGuidelines) сторонний код.
угу, легко. но порой доо..оолго :)
;) ну ты я думаю знаешь причины - обязательное сканирование кода (полу-)автоматизированной системой на предмет патентных ограничений, ручной ревью кода и общая загруженность разработчиков...
Я прошу прощения что вмешиваюсь не по теме,
но просто стало интересно - что это "обязательное сканирование кода (полу-)автоматизированной системой на предмет патентных ограничений"? Как работает и что даёт?


Название: Re: QList + qSort
Отправлено: shadone от Март 02, 2010, 12:43
Я прошу прощения что вмешиваюсь не по теме,
но просто стало интересно - что это "обязательное сканирование кода (полу-)автоматизированной системой на предмет патентных ограничений"? Как работает и что даёт?
я не знаю как конкретно это работает - какая-то система которая снанирует принимаемый код на предмет наличия запатентованных кусков кода или кода из сторонних проектов (pattern analysis вероятно). Что дает - замедляет прием больших патчей как минимум на пару недель ;)


Название: Re: QList + qSort
Отправлено: BigZ от Март 02, 2010, 12:52
Я прошу прощения что вмешиваюсь не по теме,
но просто стало интересно - что это "обязательное сканирование кода (полу-)автоматизированной системой на предмет патентных ограничений"? Как работает и что даёт?
я не знаю как конкретно это работает - какая-то система которая снанирует принимаемый код на предмет наличия запатентованных кусков кода или кода из сторонних проектов (pattern analysis вероятно). Что дает - замедляет прием больших патчей как минимум на пару недель ;)
Интересно, ни когда про такое не слышал.


Название: Re: QList + qSort
Отправлено: ритт от Март 02, 2010, 14:20
моё мнение - это фэйк :)
зато, когда (тьфу-тьфу) какой-нибудь гнусный суперсофтмегагруп потребует с нокии деньгу за то, что, мол, в кутэ куски их патентованного кода, нокия ответит: "хрен вам! мы сканируем все сторонние контрибуции нашей (полу-)автоматизированной системой на предмет патентных ограничений и вашего кода ни разу не видели" :)

с другой стороны, контора серьёзная и не стала бы (наверное) тратить ресурсы на фэйк, но я в упор не понимаю одного - если я работаю в какой-нибудь фирмочке, плодящей закрытые программные продукты, КАК нокия проверит, что моя контрибуция не содержит кусков кода из какого-нибудь из этих-самых закрытых программных продуктов? правильный ответ - никак...


Название: Re: QList + qSort
Отправлено: udovolstvie от Март 02, 2010, 15:03
Здравствуйте, коллеги.
У меня есть еще такой интересный вопрос.
Я использую qSort на массиве точек. Точка описана классом Point.
Point (float x, float y, float z);
если в операторе "<" выполняется следующее дествие:
return (x<rh.x);
То все отлично. Массив точек упорядочивается по x.
Если оператор выполняет следующее действие:
return (x<rh.x && y<rh.y && z<rh.z); или return (x<rh.x && y<rh.y);
То массив не сортируется вообще никак. То есть он сортируется, выборочно, кусками. И не правильно при этом.
Может быть, здесь есть какой то прикол???


Название: Re: QList + qSort
Отправлено: shadone от Март 02, 2010, 15:35
return (x<rh.x && y<rh.y && z<rh.z); или return (x<rh.x && y<rh.y);
То массив не сортируется вообще никак. То есть он сортируется, выборочно, кусками. И не правильно при этом.
Может быть, здесь есть какой то прикол???
"прикол" в том что это совершенно неверно.
попробуйте подумать как отсортировать например (5,0) и (4, 1).


Название: Re: QList + qSort
Отправлено: ритт от Март 02, 2010, 16:38
ddenis, +1 :)

/* запостить на бор, что ли?)) */


Название: Re: QList + qSort
Отправлено: udovolstvie от Март 02, 2010, 16:42
все верно. должно быть false. согласен, результат будет негодный. но он же (результат) должен быть!
а вот (5, 0) и (4, -1) должны быть упорядочены. Однако, даже этого не происходит.


Название: Re: QList + qSort
Отправлено: Igors от Март 02, 2010, 23:30
Здравствуйте, коллеги.
У меня есть еще такой интересный вопрос.
Я использую qSort на массиве точек. Точка описана классом Point.
Point (float x, float y, float z);
если в операторе "<" выполняется следующее дествие:
return (x<rh.x);
То все отлично. Массив точек упорядочивается по x.
Если оператор выполняет следующее действие:
return (x<rh.x && y<rh.y && z<rh.z); или return (x<rh.x && y<rh.y);
То массив не сортируется вообще никак. То есть он сортируется, выборочно, кусками. И не правильно при этом.
Может быть, здесь есть какой то прикол???
Я делаю так
Код:
bool Point::operator < ( const Point & sec ) const
{
// первый ключ x
  if (x < sec.x) return true;
  if (x > sec.x) return false;

// второй ключ y
  if (y < sec.y) return true;
  if (y > sec.y) return false;

// третий ключ z
  if (z < sec.z) return true;
  return false;
}


Название: Re: QList + qSort
Отправлено: udovolstvie от Март 03, 2010, 11:56
Спасибо, Igors!


Название: Re: QList + qSort
Отправлено: niXman от Март 03, 2010, 14:37
долго наблюдал за этой темой. не удержался ;)
http://www.boost.org/doc/libs/1_42_0/doc/html/intrusive/intrusive_vs_nontrusive.html

зы
старая добрая программерская мудрость гласит: все уже написано.