Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>P.S. boost::exception использовать не могу, компилятор в проекте gcc 3.2.3 слишком старый, не компилит boost::exception
AP>прикрепил минимальный рабочий пример.
можно вытащить оператор<< наружу:
template<typename E, typename T>
typename boost::enable_if<
boost::is_base_of<base_error, E>
, E >::type
operator<<( E e, const T &str )
{
std::ostringstream os;
os << e.m_what << str;
e.m_what = os.str();
return e;
};
enable_if проконтролирует, что оператор будет применяться только к наследникам base_error.
Надеюсь, что gcc 3.2.3 сможет это переварить.
ЗЫ Ничего, что у тебя на каждый чих копируется m_what? Я бы сделал отдельное решение для конкатенации всего в строчку (оно еще во многих местах пригодится) и только в самом конце уже засовывал результат в объект исключения.
ЗЗЫ конструктор копирования std::string может бросить исключение, что чревато terminate. Такие классы лучше не использовать внутри исключений.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Помогите, пожалуйста, решить вопрос потери исходного типа исключения. Своих знаний не хватает.
Есть иерархия исключений. У базового класса определён operator<< для сохранения диагностической информации.
При кидании исключения с добавлением информации через operator<< изначальное исключение приводится к базовому, а хочется чтобы осталось то же самое.
P.S. boost::exception использовать не могу, компилятор в проекте gcc 3.2.3 слишком старый, не компилит boost::exception
прикрепил минимальный рабочий пример.
throw range_err(); // работает нормально
а вот
throw range_err() << "Hello world!"; // приводит тип исключения к base_error, а хочу чтобы остался range_err, как быть?
#include <iostream>
#include <sstream>
using namespace std;
/**
* Базовый класс исключений общ канальных драйверов
*/struct base_error : public virtual std::exception
{
template<typename T> base_error& operator<<(const T &str)
{
std::ostringstream os;
os << m_what << str;
m_what = os.str();
return *this;
};
virtual ~base_error() throw () {};
virtual const char * what() const throw() { return m_what.c_str(); }
protected:
base_error() : std::exception() {}; // блокируем возможность кидать исключения base_errorprivate:
std::string m_what;
};
struct run_error : public base_error {};
struct range_err : public run_error {}; ///< выход за пределы чего-нибудь (например, массива или вектора)int main(int argc, char *argv[])
{
// тут нормальноtry
{
throw range_err();
}
catch(const range_err &e)
{
cout << "Good" << endl;
}
// тут происходит подмена типа исключенияtry
{
throw range_err() << "Hello world!";
}
catch(const range_err &e)
{
// хочу поймать здесь
cout << "Good" << endl;
}
catch(const base_error &e)
{
// ловлю здесь
cout << "base_error, want range_error" << endl;
}
return 0;
}
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP> Здравствуйте, Коллеги.
AP>Помогите, пожалуйста, решить вопрос потери исходного типа исключения. Своих знаний не хватает. AP>Есть иерархия исключений. У базового класса определён operator<< для сохранения диагностической информации. AP>При кидании исключения с добавлением информации через operator<< изначальное исключение приводится к базовому, а хочется чтобы осталось то же самое.
Убрать operator<< и сделать инициализацию через конструктор?
ЗЫ: Мейрс, кажется, советует делать operator<< свободной функцией.
Здравствуйте, 13akaEagle, Вы писали:
E>Убрать operator<< и сделать инициализацию через конструктор?
Тогда придётся для каждого типа исключения писать реализацию этого конструктора
Правильно понял идею?
Кстати, интересно, оно всё подставится, или таки реально будет что-то считать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>enable_if проконтролирует, что оператор будет применяться только к наследникам base_error.
J>Надеюсь, что gcc 3.2.3 сможет это переварить.
Ура , он это СМОГ
J>ЗЫ Ничего, что у тебя на каждый чих копируется m_what? Я бы сделал отдельное решение для конкатенации всего в строчку (оно еще во многих местах пригодится) и только в самом конце уже засовывал результат в объект исключения. J>ЗЗЫ конструктор копирования std::string может бросить исключение, что чревато terminate. Такие классы лучше не использовать внутри исключений.
Да, главное я упустил : поимку исключения по копии,- косяк. СПАСИБО.
Тут есть такая беда, что мы никак не контролируем, что в конце кто-то напишет таки throw_it или set_text или ещё чего.
Но можно сделать RT проверку. Например в конструкторе копии или в деструкторе text_builder_impl.
Типа запоминать в объекте, что у него уже забрали созданный текст, а если не забрали, но уже что-то в него вывели, то assert, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
AP>Правильно понял идею? AP>по-моему, сложнее сопровождать больше кода.
Один раз макрос написать.
E>>ЗЫ: Мейрс, кажется, советует делать operator<< свободной функцией. AP>посмотрю.
Извиняюсь, это был Саттер в своей задаче 5.3 из "решение сложных задач".
Здравствуйте, Erop, Вы писали:
E>Ха. Если написание таких кудрявых и нечитабельных макросов никого не парит, то нафига козе баян вообще?
Нет, не парит По крайней мере в данном контексте проще использовать макрос, чем идеальное решение на шаблонах. Сугубо личное мнение.
Такой макрос я понимаю лучше, чем кучку вычурного кода на шаблонах
E>
Очень логично.
Аналогичное решение мы рассматривали, только тогда придётся два макроса использовать, один с параметрами, другой без.
К сожалению, перегрузки макросов не поддерживается.
Хотя, может оно и правильно. Спасибо, будем голосовать на командном совещании
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>std::string в теле исключения, как рекомендовал jazzer, заменить на shared_ptr<const char *> ?
Возможно я не в курсе, и shared_ptr<const char *> имеет какую-то необычную семнтику?
Может речь шла о shared_ptr<char>?
По идее shared_ptr<char> потребует использовать нестандартную функцию деаллокации (второй параметр конструктора, если я не ошибаюсь), так как функция деаллокации по умолчанию использует delete, а не delete []
Или там для char отдельная фича какая-то?
Я бы, по простому, использовал бы std::vector<string> и не страдал. Всё равно исключения кидаются редко, так что экономить лишнюю аллокацию смысла немного. Если есть смысл, то можно сделать свою "безопасно копируемую" строку...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>Нет, не парит По крайней мере в данном контексте проще использовать макрос, чем идеальное решение на шаблонах. Сугубо личное мнение.
Ну, шаблонное решение проще отлаживать обычно. Хотя от решения, конечно, зависит.
Ну и бывают ценностные выборы, типа того, что "никаких неочевидных макросов"
IMHO, решение с text_builder( my_exception() ) << "param1 : " << param1 << "param2 : " << param2 << throw_it; не такое уж и сложное.
AP>Хотя, может оно и правильно. Спасибо, будем голосовать на командном совещании
Ну удачи.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Я в прошлом сообщении допустил ошибку!
Вместо:
E>Я бы, по простому, использовал бы std::vector<string> и не страдал. Всё равно исключения кидаются редко, так что экономить лишнюю аллокацию смысла немного. Если есть смысл, то можно сделать свою "безопасно копируемую" строку...
надо читать
Я бы, по простому, использовал бы shared_ptr<string> и не страдал. Всё равно исключения кидаются редко, так что экономить лишнюю аллокацию смысла немного. Если есть смысл, то можно сделать свою "безопасно копируемую" строку...
, конечно же
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском