1786
|
Программирование / С/C++ / Re: Где взять информацию про имеющиеся классы исключений на Си++?
|
: Март 03, 2011, 14:35
|
Ну это сильно проигрывает обычному exception
- код не прерывается, надо вставлять return, если ф-ция глубоко вложена - то везде по стеку
- напр. человек разрабатывает класс пока не заботясь как он будет использоваться. Но он уже должен иметь ввиду некую систему, полагать что в дальнейшем (каждый) пользователь класса свяжет "слот-сигнал веники" до того. А тот пользователь в еще более неловком положении потому что Вы заставляете его изучать Вашу систему Улыбающийся Если напиcано throw - сразу ясно, а кто такой exception_type? Надо разбираться - а зачем?
Ну я с Вами тут не соглашусь. И вот почему: 1) Если ошибка настолько ужасна, что продолжать программу дальше нельзя, то стандартные исключения здесь очень кстати. После блока catch всё и закончится.. А вот если есть надежда, что обработчик исключения всёже как то исправит ситуацию, то нужно позаботится о том, чтобы заново повторить тот фрагмент, где было вызвано исключение. И вот здесь начинается самое весёлое. Т.е. после обработки исключения в блоке catch Вам придётся явно! вернуть управление к точке возникновения ошибки. Как? Помещать блок try в бесконечный цикл? Нет уж, спасибо)) - напр. человек разрабатывает класс пока не заботясь как он будет использоваться. Но он уже должен иметь ввиду некую систему, полагать что в дальнейшем (каждый) пользователь класса свяжет "слот-сигнал веники" до того. А тот пользователь в еще более неловком положении потому что Вы заставляете его изучать Вашу систему
А я например могу не заставлять пользователя явно связывать сигнал со слотом. Это можно сделать в конструкторе класса, который занимается расчётами. И вместо класса ExceptionHandler, я могу определить просто функцию: C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" #include "messenger.h" using namespace std; typedef ssc::messenger3<string, string, double&> exception_type; int funcF(double x, double y) { // Пример функции, кидающей обычное исключение if (x == 0.0) throw exception_type("funcF", "divizion by zero", x); return y / x; } void exceptionHandler(const exception_type &e) { // Функция обработки исключений cout << e.arg1 << endl; cout << e.arg2 << endl; cout << e.arg3 << endl; const double epsilon = 0.0000001; e.arg3 = epsilon; } class SomeClass { public: SomeClass() { // В самом конструкторе соединяем наши сигналы с обработчиками exception.connect(exceptionHandler); } ssc::signal<const exception_type &> exception; double func(double x) { if (x == 0.0) exception(exception_type("func", "divizion by zero", x)); return 1.0 / x; } }; int main() { SomeClass sc; // Создаём наш клас и всё.. double res = sc.func(0.0); /* Проблемный момент, но мы хотим исправить ситуацию не прерывая программу! */ cout << "res = " << res << endl; // До этой точки мы дойдём! try { double res = funcF(0.0, 1.0); // А вот функция, кидающая обычные исключения cout << "res = " << res << endl; // Сюда мы уже не попадём!! (без лишниз телодвижений) } catch (exception_type e) { cout << e.arg1 << endl; cout << e.arg2 << endl; cout << e.arg3 << endl; const double epsilon = 0.0000001; e.arg3 = epsilon; // Вот на этом всё и закончится) } return 0; }
Поэтому это ещё спорный вопрос, что удобней))
|
|
|
1787
|
Программирование / С/C++ / Re: Где взять информацию про имеющиеся классы исключений на Си++?
|
: Март 03, 2011, 12:52
|
Мне вообще, исключения не очень симпатичны.. Я их не использую, к тому же сейчас есть механизм сигнал-слот, который более изящно справляется с этим всем.
Хорошее словцо "изящно", но по-моему исключения и сигналы никак не альтернатива друг другу. Не видно даже такого примера когда вместо exception можно сигналить или наоборот. [/quote] Ну вот смотрите: На примере деления на ноль. 1) У нас есть класс SomeClass, который реализует всякие там мат. вычисления.. Ниже код с пояснениями самой идеи. (использовал libssc) C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" #include "messenger.h" using namespace std; typedef ssc::messenger3<string, string, double&> exception_type; // Это класс, который содержит информацию о том что произошло и где это произошло.. ну и т.д. /* Вот этот класс и для простоты он имеет только одну функцию */ class SomeClass { public: ssc::signal<const exception_type &> exception; // сигнал - замещает исключения double func(double x) { if (x == 0.0) // пытаемся делить на ноль! exception(exception_type("func", "divizion by zero", x)); /* Шлём сигнал об этом безобразии, указывая также имя функции, где это произошло, что произошло, и ссылку на x*/ return 1.0 / x; } }; /* Класс обработчик исключений */ class ExceptionHandler : public ssc::trackable { public: void handleEvent(const exception_type& e) { /* Выводит информацию о том что случилось и */ cout << e.arg1 << endl; cout << e.arg2 << endl; cout << e.arg3 << endl; const double epsilon = 0.0000001; e.arg3 = epsilon; // Вмешивается в дальнейший процесс, изменяя наш x! } }; int main() { SomeClass sc; // создаём наш класс ExceptionHandler eh; // создаём класс обработчик sc.exception.connect(&eh, &ExceptionHandler::handleEvent); // коннектим их double res = sc.func(0.0); // Вызываем функцию в нуле! cout << res << endl; // и что же получаем?? return 0; }
Ну вот приммерно так..
|
|
|
1788
|
Разное / Говорилка / Re: Покупка в США и выбор посредника.
|
: Март 02, 2011, 23:33
|
Не знаю как насчёт americansale.ru, но у меня остались хорошие впечатления от eBay. Заказывал там как то сначала фотик, потом объектив. Связался с селлером, договорились что да как и все дела)) Всё было доставлено в лучшем виде)
|
|
|
1789
|
Программирование / С/C++ / Re: Где взять информацию про имеющиеся классы исключений на Си++?
|
: Март 02, 2011, 21:04
|
Интересно, а правильно ли я понял, что для математических особых ситуаций мне потребуется самому создавать классы, если не пользоваться сторонними библиотеками (например для ситуации деления на ноль)?
Боюсь вам придётся переписывать все функции в которых потенциально возможно появление неприятностей. Мне вообще, исключения не очень симпатичны.. Я их не использую, к тому же сейчас есть механизм сигнал-слот, который более изящно справляется с этим всем. ЗЫ: тут в соседней ветке (про преобразование интов и флоатов) нечто подобное обсуждается.
Собственно, как я понял это и есть логическое продолжение той ветки)) Автор тот же))
|
|
|
1792
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Март 02, 2011, 16:11
|
Зарелизел третью версию libssc Вненсены следующие изменения: 1) mem_fun_connection и fun_connection теперь ничего не знают о signal, что делает их более обособленными (самодостаточными) 2) В signal теперь список соединений содержит не указатели, а counted_ptr на base_connection, что повышает безопасность 3) Функции connect, disconnect перенесены в signal 4) в signal добавлены функции C++ (Qt) void disconnect_all() // разрывает все сондинения
и C++ (Qt) size_t slot_count() const // колличество всех соединений
5) Добавлены шаблонные классы messenger4, messenger3, messenger2, содержащие набор данных из 4, 3 и 2 полей соответственно: C++ (Qt) template <class T_arg1, class T_arg2> class messenger2 { public: template <class T1, class T2> messenger2(const messenger2<T1, T2> &other) : arg1(other.arg1), arg2(other.arg2) {} messenger2() {} messenger2(const T_arg1 &_arg1, const T_arg2 &_arg2) : arg1(_arg1), arg2(_arg2) {} T_arg1 arg1; T_arg2 arg2; }; //----------------------------------------------------------------------------- template <class T1, class T2> inline bool operator== (const messenger2<T1, T2> &p1, const messenger2<T1, T2> &p2) { return ((p1.arg1 == p2.arg1) && (p1.arg2 == p2.arg2)); } //----------------------------------------------------------------------------- template <class T1, class T2> inline bool operator!= (const messenger2<T1, T2> &p1, const messenger2<T1, T2> &p2) { return ((p1.arg1 != p2.arg1) || (p1.arg2 != p2.arg2)); } //-----------------------------------------------------------------------------
Пример использования: C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" #include "messenger.h" using namespace std; typedef ssc::messenger4<int, int, string, int> dataA; typedef ssc::messenger4<float, double, string, int> dataB; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } void run() { sig_a1(3.14); sig_a2(dataA(1, 2, "Hello!", 3)); } ssc::signal<float> sig_a1; ssc::signal<const dataA &> sig_a2; }; //----------------------------------------------------------------------------- class B : public ssc::trackable { public: B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } void slot_b1(int x) { cout << "slot_b(int), i = " << x << endl; } void slot_b2(const dataB &x) { cout << "slot_b2(const dataB &)" << endl; cout << x.arg1 << endl; cout << x.arg2 << endl; cout << x.arg3 << endl; cout << x.arg4 << endl; } void slot_b2(const dataA &x) { cout << "slot_b2(const dataA &)" << endl; cout << x.arg1 << endl; cout << x.arg2 << endl; cout << x.arg3 << endl; cout << x.arg4 << endl; } void slot_b2() { cout << "slot_b2()" << endl; } }; //----------------------------------------------------------------------------- int main() { A *a = new A; B *b = new B; a->sig_a1.connect(b, &B::slot_b1); // соединение с неперегруженным слотом /* Слот slot_b2 - перегружен, поэтому необходимо указывать явно параметры шаблонов */ a->sig_a2.connect<B, void, const dataB &>(b, &B::slot_b2); /* Note: сигнал отправляет тип dataA, а слот принимает тип dataB и это сработает! */ a->sig_a2.connect<B, void, const dataA &>(b, &B::slot_b2); a->sig_a2.connect<B, void>(b, &B::slot_b2); // И этот слот также сработает a->run(); delete a; delete b; return 0; }
P.S. Протестировано Valgrind'ом, утечек не обнаружено.
|
|
|
1793
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 28, 2011, 20:44
|
Ясненько) Значит так просто я не смогу посылать сигналы из одного потока, скажем объекту в другом.. Вернее смогу но нет гарантий, что при выполнении слота, другой поток не прибьёт этот объект. Или хранить в сигнале не указатели на объекты, а умные указатели (counted_ptr - он же smart_ptr в прошлом) Несколько обновил код, в частности, 1) smart_ptr теперь называется counted_ptr 2) метод void set(bool flag) в классе trigger перенёс в private: C++ (Qt) class trigger { public: trigger() : _flag(true) {} bool get() const { return _flag; } friend class trackable; private: void set(bool flag) { _flag = flag; } bool _flag; };
чтоб никто, кроме trackable не мог изменить состояние объекта. 3) Всё же поскольку случай частный, оставил только передачу одного аргумета (в том числе и void) не думаю что это вызовет неудобства, зато сразу кода скока поубавилось)
|
|
|
1794
|
Программирование / С/C++ / Re: Как правильно сделать преобразование для целых и вещественных чисел?
|
: Февраль 28, 2011, 18:40
|
Ёлки зелёные)) И всё же почему в классе NNumeric не хранить переменную в double? Всё равно NNumeric у вас весит больше 4 байт. А вместо операций, например в такой: C++ (Qt) inline float Value() const {return this->data._value;} делать следующее: C++ (Qt) inline float Value() const { double d = fabs(this->data._value); bool sign = (this->data._value >= 0.0); if (d > std::numeric_limits<float>::max()) return (sign) ? std::numeric_limits<float>::max() : -std::numeric_limits<float>::max(); if (sign) return (d > std::numeric_limits<float>::min()) ? float(d) : float(0); return (d > std::numeric_limits<float>::min()) ? float(-d) : float(0); }
double то Вам точно хватит)
|
|
|
1795
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 28, 2011, 16:23
|
И ещё такой вопрос по поводу потокобезопасности: Правильно ли то, чтобы гарантировать потокобезопасность соединения необходимо сделать операцию C++ (Qt) spy->set(false);
в деструкторе класса trackable атомарной? Вот код trackable и trigger: C++ (Qt) #ifndef TRACKABLE_H #define TRACKABLE_H #include "smart_ptr.h" namespace ssc { class trigger { public: trigger() : _flag(true) {} void set(bool flag) { _flag = flag; } bool get() const { return _flag; } private: bool _flag; }; //----------------------------------------------------------------------------- class trackable { public: trackable() { spy = smart_ptr<trigger>(new trigger); } virtual ~trackable() { spy->set(false); // Вот это должно быть атомарным? } smart_ptr<trigger> spy; }; //----------------------------------------------------------------------------- } /* namespace ssc*/ #endif // TRACKABLE_H
Или нужно что то большее
|
|
|
1797
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 27, 2011, 14:58
|
По этому принципу сделал ещё одно обобщение. Теперь можно соединять сигналы со слотами, у которых число аргументов может быть и меньше, чем число аргументов у сигнала. Например сейчас можно подсоединить сигнал C++ (Qt) ssc::signal<int, float> sig;
например с такими слотами: C++ (Qt) void slot1(); void slot2(int); void slot3(int, float); // (float, int); (double, double); (int, int) и т.д. Note: если имеется несколько перегруженных слотов, то чтоб компилятор понял какой имменно слот подключать к сигналу, нужно явно в шаблонной функции connect указать параметры шаблонов. прмер: C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" #include <cmath> class A { public: ssc::signal<int> sig_a2; ssc::signal<const double &, int> sig_a; void run() const { sig_a(M_PI, 123); sig_a2(1); } }; class B : public ssc::trackable { public: /* Класс B имеет 2 перегруженных слота */ void slot_b(float x, int y) { std::cout << "slot_b, x = " << x << std::endl; std::cout << "slot_b, y = " << y << std::endl; } void slot_b() { std::cout << "slot_b" << std::endl; } void other_slot() { std::cout << "other slot" << std::endl; } }; int main() { A *a = new A; B *b = new B; /* Для того, чтоб не смущать компилятор, нужно в этом случае явно указывать типы шаблонов */ ssc::connect<B, void, float, int, const double&, int>(a->sig_a, b, &B::slot_b); ssc::connect<B, void, const double &, int>(a->sig_a, b, &B::slot_b); /* А здесь всё как обычно, компилятор сам справится */ ssc::connect(a->sig_a2, b, &B::other_slot); a->run(); delete b; delete a; return 0; }
|
|
|
1798
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 27, 2011, 01:01
|
А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Теперь можно)) Решение неожиданно оказалось очень простым без всяких лишних введений посредника c. Короче, теперь будет работать и так: C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" class A { public: ssc::signal<int> sig_a; ssc::signal<const std::string &> sig_a2; void run() const { sig_a(2011); sig_a2("Hello!"); } }; class B : public ssc::trackable { public: void slot_b(float x) { std::cout << "slot_b, x = " << x << std::endl; } void slot_b2(std::string str) { std::cout << str << std::endl; } }; int main() { A *a = new A; B *b = new B; connect(a->sig_a, b, &B::slot_b); connect(a->sig_a2, b, &B::slot_b2); a->run(); delete b; delete a; return 0; }
Исходники приаттачены..
|
|
|
1799
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 26, 2011, 22:46
|
А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Хотя чисто теоретически это возможно, но потребуется некий посредник - объект между сигналом и слотом, в котором и будут храниться все соединения. Тогда типы аргументов можно писать какими угодно.. Вот простой пример, демонстрирующий эту идею: C++ (Qt) #include <iostream> #include <string> #include "signal_slot.h" class A { public: ssc::signal<int> sig_a; void run() const { sig_a(2011); } }; class B : public ssc::trackable { public: void slot_b(float x) { std::cout << "slot_b, x = " << x << std::endl; } }; class C : public ssc::trackable { public: C() {} ssc::signal<float> sig_c; void slot_c(int x) { sig_c(x); } }; int main() { A *a = new A; B *b = new B; C *c = new C; // перенаправляет сигнал connect(a->sig_a, c, &C::slot_c); connect(c->sig_c, b, &B::slot_b); a->run(); delete b; delete a; delete c; return 0; }
Вобщем идея в том, что соединения теперь нужно чтоб хранил отдельный шаблонный класс, который будет жить сам по седе и следить за всеми общающимися через него объектами.. Как то так)
|
|
|
1800
|
Qt / Кладовая готовых решений / Re: Частный случай механизма сигнал-слот
|
: Февраль 26, 2011, 22:17
|
А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Ну вообщето, то что стоит в <> и определяет тип параметра слота.. Однако, можно (но нужно ли?) сделать так, что передавать в сигнал тип, отличный от типа указанного в слоте и уж компилятор сам будет делать преобразование типов. Это делается так: в класса signal вместо: C++ (Qt) template <class T_arg1, class T_arg2 = void> class signal { ... void operator() (T_arg1 arg1, T_arg2 arg2) const { for (_const_iterator it = _list.begin(); it != _list.end(); it++) { if ((*it)->valid()) (*it)->handle_evant(arg1, arg2); } } можно заменить на C++ (Qt) template <class T_arg1, class T_arg2 = void> class signal { ... template <class U1, class U2> void operator() (U1 arg1, U2 arg2) const { for (_const_iterator it = _list.begin(); it != _list.end(); it++) { if ((*it)->valid()) (*it)->handle_evant(arg1, arg2); } }
Но я бы не стал так делать.. Короче сейчас с неполным совпадением аргументов не подключить.. А в boostЕ, кстати можно?
|
|
|
|
|