Вопрос про хорошие пользовательские классы исключений в Си++.
Хотелось бы в исключениях видеть не только способ сигнализирования что что-то произошло, но и удобный контейнер, который, можно было бы наполнить чем-то полезным.
Это конечно не какой-нибудь дамп многострочный, который наверное должен создаваться не через e.what() а через что-то специальное.
Но хотелось бы чтобы в исключение можно было напихать как минимум
char*, string, и любые другие от bool до double нативные типы.
Потому что кажется что это было бы очень удобно с точки зрения использования:
throw SomeException() << "blabla " << "index " << i << " array_size" << arr.size() и т.п.
Ну и вот теперь вопрос - кто-нибудь такое делал, и как вы это сделали?
Это достаточно легко сделать средствами STL, берём std::string, берем std::to_string() и ура, если для числовых типов обернуть шаблоном, то вероятно потребовался бы один метод на все случаи :)
Но по-моему так нестоит в исключениях. Исключения это типа такие классы которые возможно создаются в экстремальных условиях нехватки памяти, и тогда
try{
throw SomeException();
} catch (const SomeException &e) {
//можем сюда не попасть.
}
Да, да, чтобы такого не было можно закостылить внутри методов иключения, в которых может породиться другое исключение свой try-catch - но это как-то не эстетично, и наверерное нагрузочно на стек вызовов, а хочется чего-то легкого, что имело бы больше шансов на удачное создание, жизнь и уничтожение, когда осталось мало ресурсов на стеке программы, в куче и тому подобном...
Вопросы
Можно ли придумать что-то более лучшее чем:
1. std::string или динамически расширяемый char * заменить исключительно на char * константной длинны (массив) и в случае захода за длинну просто не заполнять его дальше, а конец массива сделать многоточием - что будет обозначать что это не весь текст исключения.
2. Взамен to_string напрашивается что-то из std::sprintf(buf, «%ld», value) - https://ru.cppreference.com/w/cpp/io/c/fprintf
но к сожалению не знаю/не_помню и по ссылке не нашел, что будет если в buf не хватит размера для преобразования числа в строку?
3. И немного глупый вопрос про низкий уровень: если в коде есть строка
A << val1 << val2 << val3 << val4
то как тратится программный стек на это дело?
Правильно что хоть сколько в ряд таких операторов записать то стек не потратится больше чем на размещения вызываемого метода + входящей в него переменной?
Иными словами, где-то на хабре находил статью что например switch() оператор - бывает если условий очень много и добавить еще один условный переход в него - то могут пойти лютые баги, из-за того что стек переполнился и т.п. Но со свичем видимо играет то что он должен сразу все свои ветви разместить на стеке
А вот это грубо говоря просто пошагово должно быть: A << val1 << val2 << val3 << val4
это тоже самое что
int a=0;
a+=f();
a+=f();
a+=f();
т.е. хоть «беcконечность» таких a+=f(3); сделай - это не покрошит программу, т.к. не переполнит программный стек (ну разве что, безопасно для рантайма,переполнит тип int).