Re[11]: delete в Деструкторе
От: Николай Ивченков  
Дата: 20.08.09 16:50
Оценка: +1
Юрий Жмеренецкий:

ЮЖ>И в результате получится вручную поддерживаемый стек активных обработчиков.


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

// обычная обработка исключений
try
{
    ....
}
catch (ExceptionType &)
{
    ....
}

// задаём последний обработчик (выполняемый на месте возникновения ошибки) как аргумент конструктора,
// деструктор удалит этот обработчик из списка локальных обработчиков потока
LocalExceptionHandler local_exception_handler(handler_function);


ЮЖ>Я в первую очередь говорю о случаях, когда можно исключить необходимость обработки сбойных случаев в деструкторе. Звучит противоречиво, объясню:

ЮЖ>Необходимо наличие нескольких стратегий обработки, которые можно разделить как минимум на два класса эквивалентности: В первом клиент готов обработать исключение и у него есть своя стратегия обработки. Отсутствие такой обработки рассматривается как ошибка в программе. Основная задача инициировать вызов, и в случае ошибки — предпринять какие-либо действия для выхода из состояния, в которое переходит программа после вызова некоторой функции(ий) и которое классифицируется клиентом как ошибочное. Второй класс — игнорирование результата с одновременной гарантией вызова. В этом случае, по классификации клиента, любой сбой не является ошибкой.

Мысль ясна.

ЮЖ>Приблизительно вот такой код можно использовать в обоих озвученных стратегиях:


ЮЖ>
void X::close()
{
  assert(!closed);
  if(!api::close(...))
    throw some_exception();
  assert(closed);
}

X::~X()
{
  if(!closed)
    api::close(...);
}


ЮЖ>Здесь возможная проблема — забытый вызов close для первой стратегии. Но, во-первых "отсутствие такой обработки рассматривается как ошибка в программе", во-вторых — при наличии сформулированной задачи, это не проблема(имхо).


IMHO, это всё-таки проблема, но решаемая. Забыть вызвать close всё-таки можно, и во время штатной работы программы это никак не проявится. Поэтому, вероятно, выбранную стратегию следует указывать при создании объекта, а в деструкторе проверять, был ли вызван close. Если вызова close не было, но явно такое намерение не было зафиксировано, то деструктор должен выкинуть assertion failed или сообщить о внутренней ошибке в программе каким-то иным способом. Т.е. надо что-то вроде:

enum ClosingPolicy { close_explicitly, close_soever };

....

X::X(ClosingPolicy closing_policy = close_explicitly) :
  m_closing_policy(closing_policy) {}

void X::close()
{
  if (closed)
    return;
  if (!api::close(....))
    throw some_exception();
  assert(closed);
}

X::~X()
{
  if (!closed)
  {
    assert(m_closing_policy != close_explicitly)
    api::close(....);
  }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.