1726
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 20, 2011, 14:57
|
и кто побеждает-то?
Получается весьма забавный результат: побеждает dynamic_cast Вот сам тест: C++ (Qt) #include <iostream> #include <list> #include <ctime> #include <cstdlib> #include <cstdio> using namespace std; enum type_derived { TYPE_INT, TYPE_F }; class Base { public: Base() {} virtual ~Base() {} virtual void print() = 0; virtual type_derived type() const = 0; }; class DerivedInt : public Base { public: DerivedInt(int id = 0) : m_id(id) {} void print() { /*cout << "DerivedInt, id = " << m_id << endl;*/ } type_derived type() const { return TYPE_INT; } void myFunc() { /*cout << "DerivedInt, id = " << m_id << endl;*/ } // not virtual private: int m_id; }; class DerivedF : public Base { public: DerivedF(float id = 0.0f) : m_id(id) {} void print() { /*cout << "DerivedF, id = " << m_id << endl;*/ } type_derived type() const { return TYPE_F; } void myFunc() { /*cout << "DerivedF, id = " << m_id << endl;*/ } // not virtual private: float m_id; }; typedef list<Base*> ListBase; typedef list<Base*>::iterator Iter; void generate(ListBase &l, size_t N) { for (size_t i = 0; i < N; ++i) { if (rand() % 2) l.push_back(new DerivedInt(i)); else l.push_back(new DerivedF(float(i))); } } void clearList(ListBase &l) { for (Iter it = l.begin(); it != l.end(); ++it) { delete *it; } l.clear(); } void test_dynamic_cast(ListBase &l) { Iter it = l.begin(); for(; it != l.end(); ++it) { DerivedF *obj = dynamic_cast<DerivedF*>(*it); if (obj) obj->myFunc(); } } void test_virtual_fun(ListBase &l) { Iter it = l.begin(); for(; it != l.end(); ++it) { if ((*it)->type() == TYPE_F) { DerivedF *obj = static_cast<DerivedF*>(*it); obj->myFunc(); } } } int main() { ListBase lb; size_t Num = 20000000; srand(time(0)); generate(lb, Num); clock_t tStart = clock(); test_dynamic_cast(lb); //test_virtual_fun(lb); cout << (float)(clock() - tStart) / CLOCKS_PER_SEC << endl; clearList(lb); return 0; }
Суть эксперимента такова: Есть базовый класс Base с чисто виртуальными двумя функциями print() и type(). От него наследуются два класса DerivedInt и DerivedF в которых данные функции переопределяются. Но также в этих классах я ввожу не виртуальные методы myFunc(). Далее создаётся список, содержащий указатели на базовый класс Base: C++ (Qt) typedef list<Base*> ListBase; typedef list<Base*>::iterator Iter; И заполняется объектами на DerivedInt и DerivedF (случайным образом): C++ (Qt) void generate(ListBase &l, size_t N) { for (size_t i = 0; i < N; ++i) { if (rand() % 2) l.push_back(new DerivedInt(i)); else l.push_back(new DerivedF(float(i))); } }
Затем проверяется вызовы dynamic_cast виртуальных функций: C++ (Qt) void test_dynamic_cast(ListBase &l) { Iter it = l.begin(); for(; it != l.end(); ++it) { DerivedF *obj = dynamic_cast<DerivedF*>(*it); // Один вызов dynamic_cast if (obj) obj->myFunc(); // один вызов не виртуального метода! } } void test_virtual_fun(ListBase &l) { Iter it = l.begin(); for(; it != l.end(); ++it) { if ((*it)->type() == TYPE_F) { // Один вызов виртуального метода DerivedF *obj = static_cast<DerivedF*>(*it); // Пренебрегаем издержками на вызов static_cast obj->myFunc(); // один вызов не виртуального метода! } } }
Думаю, что тест не совсем чист, поскольку я не учитываю издержки связанные с оператором static_cast
|
|
|
1727
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 20, 2011, 14:17
|
Проверил сейчас, что быстрее работает: вызов виртуальной функции или dynamic_cast: Разницы практически никакой нет, едва заметный эффект начинает появлятся только после миллиона вызовов.. Так что смысла в этой оптимизации, реально 0.
|
|
|
1728
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 20, 2011, 13:56
|
У меня тут ещё вопрос возник: Корректно ли тогда будет такая конструкция работать: C++ (Qt) class A { public: void func1() {} void func2() {} }; void *addr1 = (void*)&A::func1; void *addr2 = (void*)&A::func2; if (addr1 != addr2) ... elae ... Или с указателями на функции такое уже не пройдёт?
|
|
|
1729
|
Qt / Общие вопросы / Re: Qt _ кириллица и ASCII
|
: Март 19, 2011, 21:39
|
int simvol=(int)tt[0];
матюгаетцо: invalid cast from type 'QCharRef' to type 'int' C++ (Qt) int symbol = (int)str[0].toAscii();
Хотя гораздо логичнее делать так: C++ (Qt) QChar symbol = str[0]; QString answ=QString::number(simbol);
|
|
|
1730
|
Qt / Общие вопросы / Re: Qt _ кириллица и ASCII
|
: Март 19, 2011, 21:21
|
да здесь по-моему проблема в другом: C++ (Qt) QString tt; int simvol; QString answ; tt="П"; simvol=tt.toInt(); answ=QString::number(simvol);
Как вообще можно требовать такое преобразование: C++ (Qt) tt="П"; simvol=tt.toInt(); Может быть так: C++ (Qt) tt = "П"; int simvol=(int)tt[0]; QString answ=QString::number(simvol);
|
|
|
1731
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 19, 2011, 21:10
|
Так что не верю я что можно написать "ну очень умный код" который уж наверняка будет совместим лет на 10 вперед. Если что случится - значит того не миновать, и нечего пытаться решать проблемы до их поступления
и Сишный каст зло, потому что: 1. не имеет почти никаких ограничений (reinterpret_cast гораздо слабее), можно кастить тип, а заодно убить константность 2. трудно находится поиском 3. затуманивает смысл (не понятно, какой именно каст хотел сделать автор)
Ну конечно в таком простом примере сишный каст не страшен, но написать static_cast 1 раз не очень сложно, мне кажется. В вашем примере тоже странно выглядит, кстати: (char *) a == (char *) b, читающий на секунду задумается, почему именно char*, может это сравнение строк каких-то? Может в этих классах строки вначале? Может у них operator char * есть? Надо использовать void * для таких вещей. Когда код формально верный, то читается легче, перестаёшь всё время подозревать, что автор -- идиот.
== Мораль: Надо верить)) Хуже не будет)
|
|
|
1732
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 19, 2011, 20:56
|
Не знаю. Можно иметь в базовом классе void * addr; и его сравнивать. Но тогда в наследниках придётся колдовать с кастами, думаю эта возня не стоит результата. Стоит ли вообще оптимизировать операцию connect? Она ведь редко выполняется, гораздо реже вызова слота.
Вот я тож об этом сейчас подумал.. Оно того стоит? Если по времени вызов виртуальной функции и вызов оператора dynamic_cast одного порядка то нефиг и суетится.. Вообще в C++0x предлагали ввести мультиметоды для ускорения подобных операций (не знаю, прошёл ли пропозал). Но до светлого будущего редко случается дожить..
Ну почему же) В gcc 4.5.1 уже практически полностью поддерживает стандарт C++0x на сколько мне известно) Гоаорят, что уже лямбды можно использовать) Кстати, в libsig++ вообще не проверяется при создании нового соединения его наличие. Т.е. если подряд вызвать connect с одним и тем же слотом то слот будет повторно вызван
|
|
|
1733
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 19, 2011, 20:26
|
можно уменьшить и убыстрить так: 1. заменить size_t на void * 2. убрать у функции address атрибут virtual и =0 3. в теле address в базовом классе вернуть this (reinterpret_cast не нужен для преобразования в void*) 4. убрать address из наследников
1. Хорошо 2-4. так не получится по той причине, что мне не интересен адрес самого x_connection: я сравниваю адреса receiver, который является внутренней переменной соединения и содержит адрес объекта receiverА. надо иметь ввиду, что вызов dynamic_cast по скорости близок к вызову виртуальной функции, поэтому заменяя dynamic_cast на виртуальную функцию много не выиграешь.
Если так, то тогда получается, что нет смысла в этой оптимизации.
|
|
|
1734
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 19, 2011, 19:55
|
Собственно, вопрос возник в контексте оптимизации libssc. Там ранее при создании нового соединения или, например, при записи приоритета соединения и т.п. каждый раз проверяется весь список соединений и каждый раз при этом вызывается dynamic_cast (который по природе своей не быстр). Вот чтобы избавится от лишних его вызовов, я ввёл в базовый класс (base_connection) виртуальный метод: C++ (Qt) typedef size_t address_type // или typedef void* address_type или typedef char* address_type ... virtual address_type address() const = 0; И соответственно в унаследуемых классов этот метод определяю: C++ (Qt) address_type address() const { return reinterpret_cast<address_type>(m_receiver); }
Это всё позволяет не вызывать лишний раз dynamic_cast в функции compre: C++ (Qt) bool compare(base_connection2<S_arg1, S_arg2> *bc) const { if ((bc->type() == MEM_FUN_CONNECTION) && (bc->address() == address())) { mem_fun_connection2<S_arg1, S_arg2, R_receiver, R_return, R_arg1, R_arg2> *mfc = dynamic_cast<mem_fun_connection2<S_arg1, S_arg2, R_receiver, R_return, R_arg1, R_arg2> *>(bc); if (m_slot_is_const) return (mfc) ? (mfc->m_slot_pack.m_const_slot == m_slot_pack.m_const_slot) : false; return (mfc) ? (mfc->m_slot_pack.m_slot == m_slot_pack.m_slot) : false; } return false; }
Собственно вот.. Спасибо)
|
|
|
1736
|
Программирование / С/C++ / Re: тип size_t и сравнение указателей
|
: Март 19, 2011, 16:08
|
Т.е. корректно ли это будет всегда и везде работать? И есть ли какие-нить грабли? Не хочется делать обязывающих заявлений, но да, всегда. Практичнее/приятнее привести к (char *) вместо size_t Спасибо)) Прям камень с души) А в чём приимущество приведения к (char*) по сравнению size_t?
|
|
|
1737
|
Программирование / С/C++ / тип size_t и сравнение указателей
|
: Март 19, 2011, 15:50
|
Приветствую) У меня такой вопрос: Имеется два указателя на объекты двух разных типов (A и B). Хотелось бы сравнивать не сами указатели, а их значения приведённые к типу size_t. Вот пример: C++ (Qt) class A { ... }; class B { ... }; A *a = new A; B *b = new B; size_t address_a = reinterpret_cast<size_t>(a); size_t address_b = reinterpret_cast<size_t>(b); if (address_a != address_b) .... else .... Т.е. корректно ли это будет всегда и везде работать? И есть ли какие-нить грабли?
|
|
|
1738
|
Qt / Общие вопросы / Re: Вопрос по консольной программе(не решено)
|
: Март 19, 2011, 13:39
|
m_axВ цикле идет опрос серверов и в stdout выводится информация об опросе. Заканчивается работа по команде с консоли exit. Проблема в том, что команда readln переводит приложение в режим ожидания и прекращает работу основной функции Фактически моя задача очень похожа на вашу. У меня есть ядро, которое занимается вычислениями (очень долгими и нудными), но я могу с консоли не прирывая вычисления вводить команды, например, для вывода статуса, остановки вычислений, перезапуска и ещё кучу всяких команд. Ядро просто запускается в отдельном потоке, тогда readln не буде блокировать ядро. Могу показать исходники самого механизма, реализующего само консольное приложения и механизм общения через консоль с объектами.
|
|
|
1739
|
Qt / Общие вопросы / Re: Вопрос по консольной программе(не решено)
|
: Март 19, 2011, 12:54
|
Может проще сделать как-то так: C++ (Qt) std::string msg; std::string quitCommand = "Exit"; while (true) { std::getline(std::cin, msg); if (msg == quitCommand) { quit(); return 0; } sendEvent(msg); }
Или опишите проблему более детально, а то так очень смутно представляется что вы хотите.. Я сейчас тож пишу одно консольное приложение просто..
|
|
|
1740
|
Qt / 2D и 3D графика / Re: оптимизация paint() QGraphicsItem'а
|
: Март 18, 2011, 22:05
|
Хм.. C++ (Qt) void PolarAxis::paint(QPainter *p, const QStyleOptionGraphicsItem *option,QWidget *widget) { p->setMatrix(scale_matrix); p->drawEllipse(x-rad,y-rad,rad*2,rad*2); p->drawLine(x,y,x,y-rad); QPen *dotPen=new QPen(Qt::DashDotLine); // Зачем? dotPen->setWidthF(0.3); QVector<qreal> dashes; dashes <<10 <<10; dotPen->setDashPattern(dashes); p->setPen(*dotPen); for (int i=rad-15;i>0;i-=15) p->drawEllipse(x-i,y-i,i*2,i*2); for (int i=0; i>-360; i-=10){ p->drawLine(x,y,x+rad*cos(i*pi/180),y+rad*sin(i*pi/180)); double x2=x+(rad+20)*cos(i*pi/180+90*pi/180+rotate*pi/180)-15; double y2=y+(rad+20)*sin(i*pi/180+90*pi/180+rotate*pi/180)-7.5; p->drawText(x2,y2,30,15,Qt::AlignCenter,QString("%1").arg(abs(i))); } }
Во-первых зачем создавать dotPen в куче? Во-вторых из-за него у вас утечка, поскольку не видно где он уничтожается В-третьих C++ (Qt) void PolarPlot::resizeEvent(QResizeEvent *re) { QRect *rct=new QRect(0,0,re->size().height()-25,re->size().width()-25); // Те же грабли plotScene->setSceneRect(*rct); double h1=re->size().height(); double h2=re->oldSize().height(); double koef=h1/h2; pa->rescale(koef); //в pa объект класса PolarAxis }
всё сказанное выше, но приминительно к rct А теперь представте, что будет при интенсивном ресайзе и отрисовки..
|
|
|
|
|