best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 09:03
Оценка:
Здравствуйте, коллеги.

Задаюсь уже не первый день следующим вопросом — как организовать наиболее опрятную, грамотную, универсальную и удобную в использовании систему исключений в C++?

До недавнего времени во всех своих проектах я поступал следующим образом:
— Придерживался правила "Всегда выбрасывать исключения, если для сигнализации ошибки функции требуется больше, чем переменная типа bool в виде возвращаемого значения". Просадок в производительности в нашей предметной области это не вызывало, так что такой подход никакого заметного оверхеда не вносил.
— Имея отдельную подсистему, занимающуюся только своей задачей (например, подсистема для работы с HTTP), я заводил для неё как минимум один собственный класс исключений, наследуемый от std::exception, даже в том случае, если я не планирую добавлять в него никакого функционала в виде дополнительных функций-членов, кроме переопределённого what.

#include <boost/config.hpp>

#include <exception>
#include <string>

namespace http {

class exception : public std::exception
{
public:
  exception(const std::string& msg) : _msg(msg) {}

  /* virtual */ const char* what() const override BOOST_NOEXCEPT
  {
    return _msg.c_str();
  }

private:
  const std::string _msg;
};

// ...

} // namespace http


Минусы такого подхода следующие:
— Каждый раз при объявлении нового типа исключений приходится заниматься стандартными вещами наподобие определением конструктора, переопределением what, etc, даже несмотря на то, что их реализация всегда одна и та же. Можно, конечно, вынести код с переопределением функции-члена what в базовый класс, но неудобство с определением конструктора всё равно остаётся
— При добавлении нового функционала в класс исключения придётся добавлять сеттеры / геттеры, соответствующие члены класса, etc. Помимо того, что это не совсем элегантно, мы таким образом делаем класс исключения более "тяжеловесным", что, насколько я понимаю, немного противоречит идеологии их использования

Эти и некоторые другие минусы призвана решить часть библиотеки boost под названием boost exception. Вот, что у меня получилось в итоге:

#define MY_THROW(Ex) \
  throw Ex << base_exception::location_info(debug::location(__FILE__, BOOST_CURRENT_FUNCTION, __LINE__)) \
           << base_exception::trace_info(debug::get_call_stack())

class base_exception
  : virtual public std::exception
  , virtual public boost::exception
{
public:
  typedef boost::error_info<struct tag_backtrace, std::vector<std::string>> trace_info;
  typedef boost::error_info<struct tag_location, debug::location> location_info;
  typedef boost::error_info<struct tag_reason, std::string> reason_info;

  static reason_info reason(const std::string& str)
  {
    return reason_info(str);
  }

  template <typename T>
  const typename T::value_type* get() const
  {
    return boost::get_error_info<T>(*this);
  }

  const std::vector<std::string>& call_stack() const
  {
    if (const std::vector<std::string>* result = get<trace_info>())
    {
      return *result;
    }
    return std::vector<std::string>();
  }

  virtual std::string reason() const
  {
    if (const std::string* result = get<reason_info>())
    {
      return *result;
    }
    return std::string();
  }

  const debug::location& where() const
  {
    if (const debug::location* result = get<location_info>())
    {
      return *result;
    }
    return debug::location();
  }

  virtual const char* what() const throw() override
  {
    return boost::diagnostic_information_what(*this);
  }
};

class some_exception : public base_exception {};


Выбрасывание исключений в итоге выглядит следующим образом:

MY_THROW(some_exception())
      << base_exception::reason("Some exception");


Следовательно, на принимающей стороне, помимо описания причины возникновения ошибки, я всегда могу получить call stack и место, откуда оно было выброшено.

Правила в отношении исключений выглядят следующим образом:
— Каждый тип исключения наследуется от base_exception, который, в свою очередь, является наследником классов std::exception и boost::exception
— Благодаря тому, что базовый класс исключений наследуется от boost::exception, при помощи operator<< в него можно добавлять дополнительную информацию, которая может понадобиться пользовательскому коду
— Исключения должны (до тех пор, пока явно не понадобится обратного) выбрасываться при помощи макроса MY_THROW, который добавляет к выбрасываемому исключению call stack и место, откуда оно было выброшено

Нужна конструктивная критика данного подхода и ответ на следующий вопрос — видел, что некоторые при выбрасывании исключения добавляют к нему информацию об оригинальном типе исключения

#define MY_THROW(Ex) \
  throw Ex << base_exception::location_info(debug::location(__FILE__, BOOST_CURRENT_FUNCTION, __LINE__)) \
           << base_exception::original_type_info(typeid((Ex)).name()) \
           << base_exception::trace_info(debug::get_call_stack())


Для чего это нужно? Разве typeid в catch-блоке не даст того же результата?
avalon/1.0.433
Re: best practices по поводу исключений в C++
От: Alexander G Украина  
Дата: 24.12.13 09:33
Оценка:
boost::exception — хорош для диагностики, типа __FILE__, __LINE__.
Через BOOST_THROW_EXCEPTION можно добавить этот сахар, не вторгаясь в иерархию исключений (и при этом можно легко выбросить его в релизе, если попадание в бинарник лишней информации нежелательно).

для добавления информации о различных исключительных ситуациях можно взять boost::system::system_error с boost::system::error_code.
он же std::system_error c std::error_code.

идея там следующая: есть коды возврата, типа int или enum, туда попадают всякие существующие коды ошибок, типа HRESULT, свои вводятся через enum.
есть категории, так что разные виды кодов ошибок различаются по этим категориям, также категории отвечают за преобразование такого кода в строку.

в этом случае для своей библиотеки можно создать свою error category, тогда добавления новой исключительной ситуации — расширяется свой enum.
Русский военный корабль идёт ко дну!
Re[2]: best practices по поводу исключений в C++
От: flаt  
Дата: 24.12.13 09:59
Оценка: 6 (1)
Здравствуйте, Alexander G, Вы писали:

AG>идея там следующая: есть коды возврата, типа int или enum, туда попадают всякие существующие коды ошибок, типа HRESULT, свои вводятся через enum.

AG>есть категории, так что разные виды кодов ошибок различаются по этим категориям, также категории отвечают за преобразование такого кода в строку.
Плюс можно сделать сахар для дилеммы "исключения vs код возврата":

void sometimes_throws(int arg, std::error_code& ec = throws());

int main() {
  // throw if failed:
  try {
    sometimes_throws(0);
  } catch(std::system_error& e) {
      std::cerr << e.code();
  }

  // do not throw:
  std::error_code ec;
  sometimes_throws(0, ec);
  std::cerr << ec;
}
Re: best practices по поводу исключений в C++
От: Кодт Россия  
Дата: 24.12.13 10:11
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Задаюсь уже не первый день следующим вопросом — как организовать наиболее опрятную, грамотную, универсальную и удобную в использовании систему исключений в C++?


FH>До недавнего времени во всех своих проектах я поступал следующим образом:

FH>- Придерживался правила "Всегда выбрасывать исключения, если для сигнализации ошибки функции требуется больше, чем переменная типа bool в виде возвращаемого значения". Просадок в производительности в нашей предметной области это не вызывало, так что такой подход никакого заметного оверхеда не вносил.
FH>- Имея отдельную подсистему, занимающуюся только своей задачей (например, подсистема для работы с HTTP), я заводил для неё как минимум один собственный класс исключений, наследуемый от std::exception, даже в том случае, если я не планирую добавлять в него никакого функционала в виде дополнительных функций-членов, кроме переопределённого what.

FH>
FH>#include <boost/config.hpp>

FH>#include <exception>
FH>#include <string>

FH>namespace http {

FH>class exception : public std::exception
FH>{
FH>public:
FH>  exception(const std::string& msg) : _msg(msg) {}

FH>  /* virtual */ const char* what() const override BOOST_NOEXCEPT
FH>  {
FH>    return _msg.c_str();
FH>  }

FH>private:
FH>  const std::string _msg;
FH>};

FH>// ...

FH>} // namespace http
FH>


FH>Минусы такого подхода следующие:

FH>- Каждый раз при объявлении нового типа исключений приходится заниматься стандартными вещами наподобие определением конструктора, переопределением what, etc, даже несмотря на то, что их реализация всегда одна и та же. Можно, конечно, вынести код с переопределением функции-члена what в базовый класс, но неудобство с определением конструктора всё равно остаётся

Для этого нам даны шаблоны

(Сам я не монстр создания иерархий исключений, поэтому лишь поделюсь мыслями)
// создание плоской иерархии
template<class Tag> class tagged_exception : public std::exception { ..... };

struct foo_ex_tag {};
struct bar_ex_tag {};

try { ... throw tagged_exception<foo_ex_tag>("oh deer"); ... }
catch(tagged_exception<foo_ex_tag> const& e) { ... e.what() ... }

// миксины
template<class MixIn, class CtorArg = MixIn> class mixed_exception : public std::exception, public MixIn { ..... };

struct foo_mixin { /* дополнительные поля */ };

try { ... throw mixed_exception<foo_mixin>( foo_mixin(1,2,3) ); ... }
catch(mixed_exception<foo_mixin> const& e) { ... e.foo_member ... };

// CRTP

template<class Final> class curious_exception : public std::exception { .... static_cast<Final*>(this) ..... };

struct foo_exception : curious_exception<foo_exception> { ..... };

try { ... throw foo_exception("let eat bee", 1,2,3); ... };
catch(foo_exception const& e) { ... e.foo_member ... };


FH>- При добавлении нового функционала в класс исключения придётся добавлять сеттеры / геттеры, соответствующие члены класса, etc. Помимо того, что это не совсем элегантно, мы таким образом делаем класс исключения более "тяжеловесным", что, насколько я понимаю, немного противоречит идеологии их использования


Идеология исключений такая: try должен выполняться почти бесплатно, на throw можно и раскошелиться, а каскад catch — дёшево.
Поэтому само исключение можно делать тяжёлым (и кидать его как можно реже), но сопоставление лучше делать именно на уровне типов, а не
catch(e){ if(!we_can_handle(e)) throw; } ... }


Код, обменивающийся исключениями, как нуклоны — виртуальными частицами, — это смерть производительности.
Перекуём баги на фичи!
Re: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 10:14
Оценка: 7 (1)
Здравствуйте, FrozenHeart, Вы писали:

FH>
FH>class exception : public std::exception
FH>{
FH>public:
FH>  exception(const std::string& msg) : _msg(msg) {}

FH>  /* virtual */ const char* what() const override BOOST_NOEXCEPT
FH>  {
FH>    return _msg.c_str();
FH>  }

FH>private:
FH>  const std::string _msg; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
FH>};

всегда поражался такой практике, выделать память при выбросе исключений =)
искать последствия такой ситуации будет мучительно больно.

зы
#define STR_(t) #t
#define STR(t) Str_(t)
#define MY_THROW(type, msg) \
   throw type(__FILE__ "(" STR(__LINE__) "): " msg)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 10:16
Оценка:
комент не туда вписал %)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 10:26
Оценка:
AG> Через BOOST_THROW_EXCEPTION можно добавить этот сахар, не вторгаясь в иерархию исключений (и при этом можно легко выбросить его в релизе, если попадание в бинарник лишней информации нежелательно).

Да, там это уже есть, однако:
— Под капотом он использует __FILE__, который, в зависимости от того или иного компилятора, может раскрыться как в полный путь к файлу, так и отдельно само название файла. Мне, например, нужно лишь второе (наблюдать огромный путь в логах не самое приятное занятие)
— Макрос BOOST_THROW_EXCEPTION не добавляет к выбрасываемому исключению call stack

AG> для добавления информации о различных исключительных ситуациях можно взять boost::system::system_error с boost::system::error_code.

AG> он же std::system_error c std::error_code.

Так зачем, если удобнее сделать это в виде исключений с получением полного стек трейса и подробным описанием возникшей ошибки? Комбинировать std::system_error с исключениями, честно говоря, не вижу смысла. Может, я чего-то не понимаю?
avalon/1.0.433
Re[2]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 10:31
Оценка:
X> всегда поражался такой практике, выделать память при выбросе исключений =)
X> искать последствия такой ситуации будет мучительно больно.

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

X> зы

X>
X> #define STR_(t) #t
X> #define STR(t) Str_(t)
X> #define MY_THROW(type, msg) \
X>    throw type(__FILE__ "(" STR(__LINE__) "): " msg)
X>


Можно и так, вот только пользователь той или иной подсистемы может захотеть получить лишь описание ошибки, без всякой дополнительной ерунды, которая ему в данном случае никак не поможет. Более того, вот захочу я добавить стек трейс. Что я должен буду сделать? Добавить его в виде текстового представления всё в ту же строку? В каком именно формате? Всегда? Не лучше ли дать решить это самому пользователю?
avalon/1.0.433
Re[3]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 10:32
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>- Под капотом он использует __FILE__, который, в зависимости от того или иного компилятора, может раскрыться как в полный путь к файлу, так и отдельно само название файла. Мне, например, нужно лишь второе (наблюдать огромный путь в логах не самое приятное занятие)

это можно обработать в компайл-тайме.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 10:32
Оценка:
f> Плюс можно сделать сахар для дилеммы "исключения vs код возврата":

А зачем может понадобиться комбинировать исключения с кодами ошибок? Не лучше ли на этом этапе вместо числа получить подробный текст, описывающий, что же на самом деле произошло?
avalon/1.0.433
Re[3]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 10:34
Оценка: -1
Здравствуйте, FrozenHeart, Вы писали:

FH>Можно и так, вот только пользователь той или иной подсистемы может захотеть получить лишь описание ошибки, без всякой дополнительной ерунды, которая ему в данном случае никак не поможет. Более того, вот захочу я добавить стек трейс. Что я должен буду сделать? Добавить его в виде текстового представления всё в ту же строку? В каком именно формате? Всегда? Не лучше ли дать решить это самому пользователю?


эта удобность может обойтись слишком дорого.
имени файла и строки, достаточно для выявления ошибки в 99%.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 10:38
Оценка: +1
я к такому правилу пришел постепенно. сначала я отказался от выделения памяти при выбросе исключения, путем использования предаллоцирования пула строк. это уже было лучше. потом наступила ситуация, когда даже этот пул строк все усложнял — отказался и от него.
сейчас не жалуюсь ни на что.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: best practices по поводу исключений в C++
От: flаt  
Дата: 24.12.13 11:16
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

f>> Плюс можно сделать сахар для дилеммы "исключения vs код возврата":


FH>А зачем может понадобиться комбинировать исключения с кодами ошибок?

Это не комбинация. Автор библиотеки (автор функции) отдаёт политику разруливания ошибок на откуп её пользователям — хотят, используют исключения, не хотят — у них есть код ошибки. По ссылке подробности.
Re[4]: best practices по поводу исключений в C++
От: PPA Россия http://flylinkdc.blogspot.com/
Дата: 24.12.13 12:20
Оценка:
Здравствуйте, niXman, Вы писали:

X>эта удобность может обойтись слишком дорого.

X>имени файла и строки, достаточно для выявления ошибки в 99%.

Т.е. исключение в недрах функции, которая зовется из разных мест это такая редкость?
или я не понял как без стека узнать кто позвал метод...
Re[5]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 24.12.13 12:43
Оценка: -1
Здравствуйте, PPA, Вы писали:

PPA>Т.е. исключение в недрах функции, которая зовется из разных мест это такая редкость?

да нет. большинство функций зовутся из разных мест

PPA>или я не понял как без стека узнать кто позвал метод...

эта информация не первостепенной важности.
зная где исключение было выброшено, позволяет сузить понимание причины его возникновения.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: best practices по поводу исключений в C++
От: McQwerty Россия  
Дата: 24.12.13 13:53
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

X>>
X>> #define STR_(t) #t
X>> #define STR(t) Str_(t)
X>> #define MY_THROW(type, msg) \
X>>    throw type(__FILE__ "(" STR(__LINE__) "): " msg)
X>>


Если это в динамической библиотеке, которая может быть выгружена — недалеко до беды с этим указателем.
Re[5]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:22
Оценка:
f> Это не комбинация. Автор библиотеки (автор функции) отдаёт политику разруливания ошибок на откуп её пользователям — хотят, используют исключения, не хотят — у них есть код ошибки. По ссылке подробности.

А почему можно отказаться от работы с исключениями и решить использовать коды ошибок? Запрещены по code style'у / особенностям платформы? Из-за проблем с производительностью, которые явно показал профилировщик?

Стоит ли вообще над этим заморачиваться? Мне просто кажется, что лучше уж меньше свободы юзерам дать в этом плане, зато чётко указать своё отношение по данному вопросу в документации, чем иметь в 90% случаев лишний код для поддержки кодов ошибок.
avalon/1.0.433
Re[4]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:22
Оценка:
X> это можно обработать в компайл-тайме.

Ну, можно. Вот только в случае BOOST_THROW_EXCEPTION как Вы это сделаете (я же именно про него в том сообщении говорил)? Переопределите макрос __FILE__ перед включением соответствующего заголовочного файла boost'а?
avalon/1.0.433
Re[5]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:22
Оценка:
X> я к такому правилу пришел постепенно. сначала я отказался от выделения памяти при выбросе исключения, путем использования предаллоцирования пула строк. это уже было лучше. потом наступила ситуация, когда даже этот пул строк все усложнял — отказался и от него.
X> сейчас не жалуюсь ни на что.

А какие проблемы-то возникали? Нехватка памяти (раз Вы заговорил про предаллоцированный пул строк)? Я просто не о подобного рода ошибках говорю.
avalon/1.0.433
Re[6]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:22
Оценка:
X> эта информация не первостепенной важности.
X> зная где исключение было выброшено, позволяет сузить понимание причины его возникновения.

Сузить, но не сократить до минимума. Хотя, всё зависит от проекта.
avalon/1.0.433
Re[4]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:22
Оценка:
X> эта удобность может обойтись слишком дорого.
X> имени файла и строки, достаточно для выявления ошибки в 99%.

Слишком дорого? А как же лишние часы, потраченные на попытку понять причину возникновения ошибки, кол-во которых могло бы уменьшиться, если бы у программиста был call stack?
avalon/1.0.433
Re[2]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 24.12.13 19:58
Оценка:
А чем такой подход лучше приведённого мной (я про вариант с наследованием от boost::exception, разумеется)?
avalon/1.0.433
Re[5]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 24.12.13 21:10
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Слишком дорого? А как же лишние часы, потраченные на попытку понять причину возникновения ошибки, кол-во которых могло бы уменьшиться, если бы у программиста был call stack?


Есть разные подходы к вопросу...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 03:53
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Сузить, но не сократить до минимума.

а еще, было бы здорово, если бы исключение само лечило причину своего выброса.

FH>Хотя, всё зависит от проекта.

а какая разница? используемая IDE не показывает вызывающих?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 03:54
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Слишком дорого? А как же лишние часы, потраченные на попытку понять причину возникновения ошибки, кол-во которых могло бы уменьшиться, если бы у программиста был call stack?

мне не нужен call-stack.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: best practices по поводу исключений в C++
От: LaptevVV Россия  
Дата: 25.12.13 04:22
Оценка: +2
Наилучшая практика — ПРОЕКТИРОВАТЬ обработку ошибок.
И по возможности — выделять это в отдельную подсистему, для полной инкапсуляции обработки.
Но так редко удается, хотя к этому надо стремиться.
Возможно, наилучшим решением был бы аспектно-ориентированный подход.
Но я не знаю подобных решений для С++.
Кто бы занялся?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 04:57
Оценка: :)
Здравствуйте, LaptevVV, Вы писали:

LVV>Наилучшая практика — ПРОЕКТИРОВАТЬ обработку ошибок.

т.е. не использовать исключения, а использовать коды ошибок?

LVV>хотя к этому надо стремиться.

зачем?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: best practices по поводу исключений в C++
От: PPA Россия http://flylinkdc.blogspot.com/
Дата: 25.12.13 05:02
Оценка: +4
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, FrozenHeart, Вы писали:
FH>>Слишком дорого? А как же лишние часы, потраченные на попытку понять причину возникновения ошибки, кол-во которых могло бы уменьшиться, если бы у программиста был call stack?
X>мне не нужен call-stack.

Это лукавство, или я не увидел в вашем профиле емайла Чака Нориса?
Может я конечно и тупой, но мне часто и стек не помогает понять причину падения,
даже если есть полные дампы — не могу однозначно получить ответ почему упало
приложение,как повторить ситуацию в отладке и исправить.

Попробуйте зайдите под гостем в краш-колектор моей программки
54202 падения при этом они сгруппированы по стеку
https://crash-server.com/AppVersion.aspx?ClientID=ppa&amp;AppVersionID=86
даже такая автоматизация не помогает локализовать все проблемы.

Год назад я задавал вопрос про одно падение, которое возникает рандомно и только на XP
http://www.rsdn.ru/Forum/winapi/4957569.1
Автор: PPA
Дата: 08.11.12

Ответа не получил.

Считаю, что стек падений может быть не нужен только в одном случае — вашим кодом никто не пользуется.
Re[7]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 05:34
Оценка:
Здравствуйте, PPA, Вы писали:

если в код вкралась какая-то нереально сложная ошибка — мы собираем продукт в релизе но с отладночной инфой, и запускаем его под дебаггером. дебагер заскриптован, и в случае чего-то неординарного — создает core-dump, сохраняет call-stack, аргументы функции, локальные переменные, и еще выполняет всякое что там в скрипте записано.
а в штатном использовании программы, ничего более чем file:line не нужно.

PPA>Считаю, что стек падений может быть не нужен только в одном случае — вашим кодом никто не пользуется.

есть три типа программистов:
1. хорошие.
2. плохие.
3. отрицающие, что они плохие.


зы
как пример, приведу ситуацию из реальной жизни. недели две назад закончил реализацию некоторого механизма зеркалирования и отката состояния группы игровых серверов. получилось ~30000 loc. код писал я сам. дебагер был использован один раз.
но, вы можете не верить, дело ваше.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[8]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 05:47
Оценка:
Здравствуйте, niXman, Вы писали:

X>если в код вкралась какая-то нереально сложная ошибка — мы собираем продукт в релизе но с отладночной инфой, и запускаем его под дебаггером.

кстати да, после того как в GCC добавили AddressSanitizer и UndefinedBehaviorSanitizer — думаю мы и вовсе перестанем использовать дебаггер для подобных случаев.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: best practices по поводу исключений в C++
От: LaptevVV Россия  
Дата: 25.12.13 05:52
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, LaptevVV, Вы писали:


LVV>>Наилучшая практика — ПРОЕКТИРОВАТЬ обработку ошибок.

X>т.е. не использовать исключения, а использовать коды ошибок?
Нет.
Проектировать — это не значит закладываться на конкретную реализацию.
Это значит, что помимо всех правильных ситуаций в системе надо спроектировать и возможные неправильные.
А потом подумать об централизованной обработке.

LVV>>хотя к этому надо стремиться.

X>зачем?
Чтобы подобных вопросов не задавать на форумах...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[8]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 25.12.13 05:56
Оценка:
X> если в код вкралась какая-то нереально сложная ошибка — мы собираем продукт в релизе но с отладночной инфой, и запускаем его под дебаггером. дебагер заскриптован, и в случае чего-то неординарного — создает core-dump, сохраняет call-stack, аргументы функции, локальные переменные, и еще выполняет всякое что там в скрипте записано.
X> а в штатном использовании программы, ничего более чем file:line не нужно.

Т.е. Вы дожидаетесь возникновения проблемы у клиентов, после чего, имея при себе лишь имя файла, название функции и строку, из которой было выброшено исключение, пытаетесь воспроизвести её на своих системах? А если воспроизвести не получится? А если вариантов вызова throw слишком много? А что, если они зависят от того, откуда именно Вы пришли в данную функцию? Не лучше ли было бы иметь при это хотя бы call stack?
avalon/1.0.433
Re[6]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 25.12.13 05:56
Оценка:
X> мне не нужен call-stack.

Вам — нет, а вот кому-то другому вполне может пригодиться.
avalon/1.0.433
Re: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 25.12.13 06:07
Оценка:
Кстати, кто-нибудь знает в итоге ответ на следующий вопрос:

FH> Нужна конструктивная критика данного подхода и ответ на следующий вопрос — видел, что некоторые при выбрасывании исключения добавляют к нему информацию об оригинальном типе исключения


FH>
FH> #define MY_THROW(Ex) \
FH>   throw Ex << base_exception::location_info(debug::location(__FILE__, BOOST_CURRENT_FUNCTION, __LINE__)) \
FH>            << base_exception::original_type_info(typeid((Ex)).name()) \
FH>            << base_exception::trace_info(debug::get_call_stack())
FH>


FH> Для чего это нужно? Разве typeid в catch-блоке не даст того же результата?
avalon/1.0.433
Re[4]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 06:08
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Это значит, что помимо всех правильных ситуаций в системе надо спроектировать и возможные неправильные.

контрактное программирование?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: best practices по поводу исключений в C++
От: LaptevVV Россия  
Дата: 25.12.13 06:16
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, LaptevVV, Вы писали:


LVV>>Это значит, что помимо всех правильных ситуаций в системе надо спроектировать и возможные неправильные.

X>контрактное программирование?
Еще ДО.
Контрактное программирование — это конкретная технология реализации.
А тут в принципе надо решать вопрос: а что будет, если случится вот это?
В одних случаях — ничего страшного.
А в других — "ой, ребята, я пошла, мне что-то нехорошо...".
А сколько я видел проектов, нигде проектирования вариантов аварийных ситуаций в голову не приходит.
Инструменты проектирования не настаивают на этом.
Только в ДРАКОНЕ — обязательными являются побочные ветви. Так он и сделан в космической отрасли.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[6]: best practices по поводу исключений в C++
От: PPA Россия http://flylinkdc.blogspot.com/
Дата: 25.12.13 06:20
Оценка:
Здравствуйте, niXman, Вы писали:
PPA>>или я не понял как без стека узнать кто позвал метод...
X>эта информация не первостепенной важности.
X>зная где исключение было выброшено, позволяет сузить понимание причины его возникновения.

Пока не понимаю.

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
        {       // try to allocate size bytes
        void *p;
        while ((p = malloc(size)) == 0)
                if (_callnewh(size) == 0)
                {       // report no memory
                static const std::bad_alloc nomem;
                _RAISE(nomem);
                }



Бросили исключение — std::bad_alloc.
файл new.cpp — номер строки 63 (VC++2010)

Какие ваши действия чтобы узнать кто собственно заказал слишком много памяти, или она действительно кончилась?
Re[9]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 09:23
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Т.е. Вы дожидаетесь возникновения проблемы у клиентов

что значит "дожидаетесь"? у нас есть отдел тестирования. значит да, дожидаемся что у конечного пользователя ничего страшного не произойдет.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[7]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 09:26
Оценка: -3 :))
Здравствуйте, PPA, Вы писали:

это же нелепый пример.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[8]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 09:46
Оценка:
Здравствуйте, niXman, Вы писали:

X>это же нелепый пример.

не могу представить, как такое может произойти у конечного юзера...
допустим, размер обрабатываемых программой абстрактных данных, приходит откуда-то извне, к примеру по сети в виде строки. но тогда тут должен быть валидатор, и это требование должно быть заложено в архитектуру.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 09:48
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Контрактное программирование — это конкретная технология реализации.

LVV>А тут в принципе надо решать вопрос: а что будет, если случится вот это?
это и есть контрактное программирование.
ты можешь как описать только допустимые условия, либо наоборот — только недопустимые.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[9]: best practices по поводу исключений в C++ OFF
От: Figaro Россия  
Дата: 25.12.13 11:26
Оценка:
Что эт за хрень?

P.S. Пользую MSVC, исторически...
avalon/1.0.433
Re[10]: best practices по поводу исключений в C++
От: skeptic  
Дата: 25.12.13 11:31
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, FrozenHeart, Вы писали:


FH>>Т.е. Вы дожидаетесь возникновения проблемы у клиентов

X>что значит "дожидаетесь"? у нас есть отдел тестирования. значит да, дожидаемся что у конечного пользователя ничего страшного не произойдет.

Поздравляю вас! У вас, пожалуй, первая в мире команда которая выпускает продукт абсолютно без багов.
Re[11]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 25.12.13 11:43
Оценка:
Здравствуйте, skeptic, Вы писали:

S>Поздравляю вас! У вас, пожалуй, первая в мире команда которая выпускает продукт абсолютно без багов.

спасибо
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: best practices по поводу исключений в C++
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 25.12.13 12:49
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Задаюсь уже не первый день следующим вопросом — как организовать наиболее опрятную, грамотную, универсальную и удобную в использовании систему исключений в C++?

Начать различать место генерации исключения, место логирования и место обработки.
Sic luceat lux!
Re[3]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 25.12.13 20:49
Оценка:
Здравствуйте, niXman, Вы писали:

LVV>>Наилучшая практика — ПРОЕКТИРОВАТЬ обработку ошибок.

X>т.е. не использовать исключения, а использовать коды ошибок?

То есть разрабатывать тактику и стратегию обработки тех или иных ситуация, и разрабатывать поддерживающий эти тактику и стратегию код...

Например, мне нравится подход, при котором исключения почти всегда кидаются только для того, что бы прибить программу, или почти прибить, а "почти" потому, что допустимо кидать исключения, которые поймают где-то рядом, локально. При этом весь код пишется так, что ожидает исключения из любого места, но при этом гарантирует только корректное разрушение данных, не особо гарантируя при этом освобождение всей памяти. Ну за исключением того локального кода, который "почти"...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 25.12.13 20:50
Оценка:
Здравствуйте, PPA, Вы писали:

PPA>Попробуйте зайдите под гостем в краш-колектор моей программки

PPA>54202 падения при этом они сгруппированы по стеку
PPA>https://crash-server.com/AppVersion.aspx?ClientID=ppa&amp;AppVersionID=86
PPA>даже такая автоматизация не помогает локализовать все проблемы.

PPA>Год назад я задавал вопрос про одно падение, которое возникает рандомно и только на XP

PPA>http://www.rsdn.ru/Forum/winapi/4957569.1
Автор: PPA
Дата: 08.11.12

PPA>Ответа не получил.

PPA>Считаю, что стек падений может быть не нужен только в одном случае — вашим кодом никто не пользуется.


Ты, вроде как, убедительно показал, что стек тебе не особо помогает...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 26.12.13 05:27
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Ты, вроде как, убедительно показал, что стек тебе не особо помогает...

без дампа аргументов функций и/или локальных переменных — он и не должен особо помогать.
говорю же — call-stack — весьма бесполезная штука.
пока не встречал ничего полезнее core-dump или запуска программы под заскриптованным отладчиком, который сделает не только call-stack, но и дамп аргументов функций и/или локальных переменных, и так для каждого фрейма из call-stack.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[9]: best practices по поводу исключений в C++
От: PPA Россия http://flylinkdc.blogspot.com/
Дата: 26.12.13 07:58
Оценка:
Здравствуйте, niXman, Вы писали:
E>>Ты, вроде как, убедительно показал, что стек тебе не особо помогает...
X>без дампа аргументов функций и/или локальных переменных — он и не должен особо помогать.
X>говорю же — call-stack — весьма бесполезная штука.

Но он ведь полезней варианта "имя файл + номер строки"?
Зачем вообще раскрутка стека существует "из коробки" в других языках программирования java/C#/...
а для С++ придумали для этого велосипеды разных цветов:
http://code.google.com/p/crashrpt/
http://code.google.com/p/google-breakpad/
а вот эти даже успешно продают своб либу для C++ Builder/Delphi
http://www.eurekalog.com/

X>пока не встречал ничего полезнее core-dump или запуска программы под заскриптованным отладчиком, который сделает не только call-stack, но и дамп аргументов функций и/или локальных переменных, и так для каждого фрейма из call-stack.


Для этого ведь нужен доступ к компу где повторяется проблема?
Как вы получаете этот доступ?
Re[10]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 26.12.13 08:43
Оценка: +1
Здравствуйте, PPA, Вы писали:

PPA>Но он ведь полезней варианта "имя файл + номер строки"?

ох и спорно...

PPA>Для этого ведь нужен доступ к компу где повторяется проблема?

нет, не нужен.

делаем так:
1. реальный исполняемый файл программы переименовываем как-то.
2. пишем другую микропрограмму, которая запускает gdb с нужными опциями так, чтоб ему скормить gdb-скрипт и имя бинаря реальной программы.
3. когда эта микропрограмма детектирует завершение gdb — она отправляет на почту файлы с дампами созданными gdb.

но в офф релизе такое недопустимо, срача и подозрений от юзеров будет огого %)
мы обычно проводим закрытое тестирование, за участие в котором юзеры получают некоторые бонусы(типа игровой бонусной валюты, которую невозможно вывести), для заинтересованности.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[10]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 26.12.13 08:45
Оценка:
Здравствуйте, PPA, Вы писали:

PPA>http://code.google.com/p/google-breakpad/

этот пробовал на линуксе — дамп создает через раз =)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[10]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 26.12.13 08:49
Оценка:
Здравствуйте, PPA, Вы писали:

только учти — gdb на венде не умеет создавать core-dump`ы.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[9]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 26.12.13 09:03
Оценка:
Здравствуйте, niXman, Вы писали:

X>говорю же — call-stack — весьма бесполезная штука.

+100500

X>пока не встречал ничего полезнее core-dump или запуска программы под заскриптованным отладчиком, который сделает не только call-stack, но и дамп аргументов функций и/или локальных переменных, и так для каждого фрейма из call-stack.


Ну ещё продуманное логгирование иногда помогает...
Ну и, опять же, лично я сторонник широко использовать штуку вроде assert, вроде, а не сам по себе assert, потому, что оно должно проверять условие не только в дебаг-версии, а всегда. Ну, например, её можно называть StrongAssert, скажем...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: best practices по поводу исключений в C++
От: PPA Россия http://flylinkdc.blogspot.com/
Дата: 26.12.13 10:04
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ну ещё продуманное логгирование иногда помогает...

E>Ну и, опять же, лично я сторонник широко использовать штуку вроде assert, вроде, а не сам по себе assert, потому, что оно должно проверять условие не только в дебаг-версии, а всегда. Ну, например, её можно называть StrongAssert, скажем...

Т.е. это теоретическое желание, или ты такое юзаешь в реальных проектах?
Расскажи подробнее как тебе помогает примитивный assert без стека вызова.
Возьмем стандартный контейнер
http://www.cplusplus.com/reference/vector/vector/at/
у него есть метод at и он даже в релизе кидает исключение о выходе за границу.
я пока не встречал извращенцев, использующих в продуктивном коде at вместо operator[]
но для чего-то этот метод придумали, значит нужен.

#include <vector>
#include <iostream>
int main()
{
    std::vector< int> v;
    std::cout << "v.at(0) = " << v.at(0) << '\n';
    return 0;
}



C:\vc10\test-vc10>c++ --version
c++.EXE (rev5, Built by MinGW-W64 project) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C:\vc10\test-vc10>c++ vector-at.cpp

C:\vc10\test-vc10>a.exe
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Информативно?
Re[11]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 26.12.13 10:56
Оценка:
Здравствуйте, PPA, Вы писали:

PPA>Т.е. это теоретическое желание, или ты такое юзаешь в реальных проектах?

Да, использую.
PPA>Расскажи подробнее как тебе помогает примитивный assert без стека вызова.
Гарантирует, что в том или ином месте те или иные пред/пост условия верны. Либо ловит, что не верны.

PPA>Возьмем стандартный контейнер

PPA>http://www.cplusplus.com/reference/vector/vector/at/
PPA>у него есть метод at и он даже в релизе кидает исключение о выходе за границу.
PPA>я пока не встречал извращенцев, использующих в продуктивном коде at вместо operator[]
PPA>но для чего-то этот метод придумали, значит нужен.

Ну можно использовать массив, который проверяет и в [], но обычно это не надо.
В целом AV не сильно хуже провала assert...

PPA>This application has requested the Runtime to terminate it in an unusual way.

PPA>Please contact the application's support team for more information.

PPA>Информативно?


Если у тебя код написан последовательно со StrongAssert'ами, то какой-то провалится раньше, чем дойдёт дело до выхода за пределы массива...

Грубо говоря последовательное применение StrongAssert, особенно в коробочных продуктах с большим числом инсталляций, решает сразу две задачи.
1) Позволяет сильно повысить эффективность тестирования.
2) Если какая-то ошибка таки доходит до релиза, то по тому, какой именно assert провалисля, обычно легко идентифицируется какая именно ошика произошла и какой воркэраунд стоит применить, если новая версия пока что почему-то клиенту недоступна...

Но в целом да, такой подход эффективен при сочетании двух обстоятельств
1) Код имеет довольно высокий уровень качества и тестирования. То есть assert у пользователя таки редкость
2) Много инсталляций.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 26.12.13 10:59
Оценка:
Здравствуйте, PPA, Вы писали:

PPA>Для этого ведь нужен доступ к компу где повторяется проблема?

PPA>Как вы получаете этот доступ?

Если речь таки идёт о логах + массовые StrongАssert's, то можно получить довольно много информации о том, что происходит, без прямого доступа. Обычно этого достаточно, что бы либо просто понять в чём проблема, либо, воспроизвести её у себя.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: best practices по поводу исключений в C++
От: wander  
Дата: 27.12.13 04:59
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

f>> Это не комбинация. Автор библиотеки (автор функции) отдаёт политику разруливания ошибок на откуп её пользователям — хотят, используют исключения, не хотят — у них есть код ошибки. По ссылке подробности.


FH>А почему можно отказаться от работы с исключениями и решить использовать коды ошибок? Запрещены по code style'у / особенностям платформы? Из-за проблем с производительностью, которые явно показал профилировщик?


Ну вот например есть у тебя среда, в которой нельзя исключения использовать. Например С-callback. Если коды не поддерживаются, то придётся ставить фильтр.

FH>Стоит ли вообще над этим заморачиваться? Мне просто кажется, что лучше уж меньше свободы юзерам дать в этом плане, зато чётко указать своё отношение по данному вопросу в документации, чем иметь в 90% случаев лишний код для поддержки кодов ошибок.


Всегда, когда есть альтернатива — это хорошо.
Re[9]: best practices по поводу исключений в C++
От: wander  
Дата: 27.12.13 05:13
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, niXman, Вы писали:


X>>это же нелепый пример.

X>не могу представить, как такое может произойти у конечного юзера...
X>допустим, размер обрабатываемых программой абстрактных данных, приходит откуда-то извне, к примеру по сети в виде строки. но тогда тут должен быть валидатор, и это требование должно быть заложено в архитектуру.

Функция at(), конструктор std::string от 0 (нестандартное, но есть), dynamic_cast, исключение ios_base::failure, и др.
Re[7]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 27.12.13 07:01
Оценка:
Здравствуйте, wander, Вы писали:

W>Ну вот например есть у тебя среда, в которой нельзя исключения использовать. Например С-callback.

что это значит?
колбяк написан на С++, но экспортируется как Си-функция?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: best practices по поводу исключений в C++
От: jazzer Россия Skype: enerjazzer
Дата: 27.12.13 07:19
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>> Для чего это нужно? Разве typeid в catch-блоке не даст того же результата?

Только если ты будешь ловить точно то, что выброшено. А если, как это обычно бывает, ты будешь ловить на живца базовый класс, то typeid в catch-блоке тебе и покажет базовый:
#include <iostream>
#include <typeinfo>
struct Base {};
struct Derived: Base {};
int main() {
  try {
    std::cout << "thrown: " << typeid(Derived).name() << std::endl;
    throw Derived();
  }
  catch (const Base& e) {
    std::cout << "caught: " << typeid(e).name() << std::endl;
  }
}

печатает:
thrown: Derived
caught: Base
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[8]: best practices по поводу исключений в C++
От: wander  
Дата: 27.12.13 07:23
Оценка:
Здравствуйте, niXman, Вы писали:

X>колбяк написан на С++, но экспортируется как Си-функция?


Да. Думаешь это редкость?
Re[9]: best practices по поводу исключений в C++
От: wander  
Дата: 27.12.13 07:29
Оценка:
Здравствуйте, wander, Вы писали:

W>Здравствуйте, niXman, Вы писали:


X>>колбяк написан на С++, но экспортируется как Си-функция?


W>Да. Думаешь это редкость?


Навскидку: libexpat, libpthread. В Win32 API частенько бывает. Да полно примеров.
Re[9]: best practices по поводу исключений в C++
От: niXman Ниоткуда https://github.com/niXman
Дата: 27.12.13 07:37
Оценка:
Здравствуйте, wander, Вы писали:

W>Думаешь это редкость?

я не думаю что это это редкость. просто хотел убедится.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: best practices по поводу исключений в C++
От: Erop Россия  
Дата: 27.12.13 09:26
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Стоит ли вообще над этим заморачиваться? Мне просто кажется, что лучше уж меньше свободы юзерам дать в этом плане, зато чётко указать своё отношение по данному вопросу в документации, чем иметь в 90% случаев лишний код для поддержки кодов ошибок.


Во-первых, если всё-таки обработку ошибок спроектировать, то вполне можно сделать так, что лишнего кода для поддержки как кодов, так и исключений, будет довольно мало.
Во-вторых, решение на кодах универсальнее, так что если уж от чего-то отказываться, то скорее от исключений, чем от кодов
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: best practices по поводу исключений в C++
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 27.12.13 10:38
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

X>> всегда поражался такой практике, выделать память при выбросе исключений =)

X>> искать последствия такой ситуации будет мучительно больно.

FH>А как иначе? Где-то же эту информацию хранить всё же надо. Ну, не в виде члена класса (я, собственно, об этом и писал, в том числе), а в каком-то другом месте.

можно просто сохранять указатель на данные в стеке, ничего страшного не произойдет

struct Err : std::exception {
    Err(const char* p) : msg_(p) {}
    
    const char* msg_;
};

...

throw Err("some error message");

...

catch(Err const& e) {
    std::cout << e.msg_ << std::endl;  // должно вывести some error message
}
Re: best practices по поводу исключений в C++
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 27.12.13 10:48
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>Здравствуйте, коллеги.


FH>Задаюсь уже не первый день следующим вопросом — как организовать наиболее опрятную, грамотную, универсальную и удобную в использовании систему исключений в C++?


Самая приятная и простая система обработки ошибок в С++, с которой мне доводилось работать, использовала коды ошибок. Все подсистемы возвращают коды ошибок, весь код написан так, словно ничто не может кинуть исключение, следовательно — не нужно париться насчет exception safety, думать о том, останутся ли данные в памяти в целостном состоянии, после обработки исключения и тд. Исключения используются только как panic — приложение кидает исключение тогда, когда не знает как обработать ошибку и желает от нее умереть. Исключения не обрабатываются и приводят к падениям, стектрейсам и дампам, которые просто анализировать, так как исключения не перевыбрасываются никогда. Ес-но исключения обрабатываются в тех случаях, когда приходится работать с кодом, написаном в другом стиле, где все ошибки возвращаются через исключения.

Подход конечно очень специфичен и не претендует на универсальность.
Re[8]: best practices по поводу исключений в C++
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 27.12.13 10:56
Оценка:
Здравствуйте, niXman, Вы писали:

X>зы

X>как пример, приведу ситуацию из реальной жизни. недели две назад закончил реализацию некоторого механизма зеркалирования и отката состояния группы игровых серверов. получилось ~30000 loc. код писал я сам. дебагер был использован один раз.
X>но, вы можете не верить, дело ваше.

Пример из реальной жизни №1 — приложение с отладочной инфой, но под отладчиком в production работать не может из-за тормозов, а если снизить нагрузку — бага не воспроизводится.

Пример из реальной жизни №2 — бага воспроизводится у клиента, а у нас не воспроизводится, а у клиента служба безопасности не разрешает удаленную отладку.

Я могу долго продлжать
Re[3]: best practices по поводу исключений в C++
От: FrozenHeart  
Дата: 27.12.13 12:15
Оценка:
С чего бы? Наследование от std::exception убирает эту проблему:

#include <exception>
#include <iostream>
#include <typeinfo>

class Base : public std::exception {};
class Derived: public Base {};

int main()
{
  try
  {
    throw Derived();
  }
  catch (const Base& ex)
  {
    std::cout << typeid(ex).name() << '\n';
  }
}


Output

class Derived

avalon/1.0.433
Re[4]: best practices по поводу исключений в C++
От: uzhas Ниоткуда  
Дата: 27.12.13 13:51
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

FH>С чего бы? Наследование от std::exception убирает эту проблему:


ссылка по теме: http://stackoverflow.com/questions/11484010/c-typeid-used-on-derived-class-doesnt-return-correct-type
Re: best practices по поводу исключений в C++
От: minorlogic Украина  
Дата: 29.12.13 10:33
Оценка:
Было бы неплохо услышать для чего вам эта система нужна. Как используются исключения и т.д.

Ну или зайти с верхов, для каких целей вообще вам нужна система исключений ?
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: best practices по поводу исключений в C++
От: Lepsik Индия figvam.ca
Дата: 30.12.13 18:19
Оценка:
FH>До недавнего времени во всех своих проектах я поступал следующим образом:
FH>- Придерживался правила "Всегда выбрасывать исключения, если для сигнализации ошибки функции требуется больше, чем переменная типа bool в виде возвращаемого значения". Просадок в производительности в нашей предметной области это не вызывало, так что такой подход никакого заметного оверхеда не вносил.


Придерживаtся правила "никогда не выбрасывать исключения, исключения для драйверов"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.