Re[9]: C++ Best Practices
От: VTT http://vtt.to
Дата: 03.11.15 09:38
Оценка: 4 (1) +1
Здравствуйте, CEMb, Вы писали:

CEM>1. все if-ы никуда не пропали, они просто где-то внутри вызовов каждой строчки, там же где и throw.


if-ы накапливаются на всей глубине стека вызовов

Вот пример без использования исключений:
auto
Method1(void) -> bool
{
  ...
  if(failed)
  {
    return(false);
  }
  ..
  return(true);
}

auto
Method2(void) -> bool
{
  ...
  if(!Method1())
  {
    return(false);
  }
  ..
  return(true);
}

auto
Method3(void) -> bool
{
  ...
  if(!Method2())
  {
    return(false);
  }
  ..
  return(true);
}

auto
Method4(void) -> bool
{
  ...
  if(!Method3())
  {
    return(false);
  }
  ..
  return(true);
}

auto
Method5(void) -> bool
{
  ...
  if(!Method4())
  {
    return(false);
  }
  ..
  return(true);
}

auto
TopMethod(void) -> void
{
  ...
  if(!Method5())
  {
    return;
  }
  ..
}


А вот пример с использованием исключений:
auto
Method1(void) -> void
{
  ...
  if(failed)
  {
    throw(t_MyException());
  }
  ..
}

auto
Method2(void) -> void
{
  ...
  Method1();
  ..
}

auto
Method3(void) -> void
{
  ...
  Method2();
  ..
}

auto
Method4(void) -> void
{
  ...
  Method3();
  ..
}

auto
Method5(void) -> void
{
  ...
  Method4();
  ..
}

auto
TopMethod(void) -> void
{
  ...
  try
  {
    Method5();
  }
  catch(t_MyException const & exception);
  {
    return;
  }
  ..
}


Количество задействованных if-ов можете подсчитать сами...
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[8]: C++ Best Practices
От: T4r4sB Россия  
Дата: 03.11.15 09:42
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Вместо этого с исключениями и деструкторами можно написать просто


Это пример о пользе деструкторов, а не о пользе исключений.
Re[9]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 09:44
Оценка: 4 (1) +1
Здравствуйте, CEMb, Вы писали:

CEM>Это всё понятно, да, и я выше писал, что такой код удобнее для исполнения и написания. Но:

CEM>1. все if-ы никуда не пропали, они просто где-то внутри вызовов каждой строчки, там же где и throw.
Это как сказать вся логика никуда не пропала, она просто где-то в других классах
CEM>2. если не поставить try/catch будет тоже самое, что не поставить if — падение программы (но в случае с try/catch у нас есть выбор снаружи, да)
Правило простое, в самом верхнем уровне всегда есть try-catch .
CEM>2.1. а, или там в случае неудачно инициализации сразу зовётся деструктор? Но всё равно, неотловленное исключение как?
Деструкторы вызовутся по порядку и только для инициализированных объектов.
CEM>2.1.1. тогда всегда ли применима схема с com_ptr (или аналогичная, так как com_ptr вроде накладывает на класс свои требования)?
CEM>2.2. вот возможность поставить try/catch где угодно, уменьшает читабельность. Или нет?


CEM>Не-не, я и не хотел я хотел только получить удобный способ и обработку пошаговой инициализации (raii это тоже всё понятно)

Для пошаговой что try-catch что коды ошибок создадут месиво.
try-catch решает проблему не пошаговой обработки, а обработки в целом.
Во многих случаях неважно вылетело на первой строке или на второй, главное что не получилось и мы хотим получить внятную ошибку, т.е. скажем передать строку с текстом.
Как это в кодах возврата делать ?
Можно конечно bool TryThis(..., string& errorString)
А если мы хотим больше чем строка ? скажем ip адрес высказать, что тогда ?

_NN>>Это как от dynamic_cast и RTTI отказаться без обоснований.

CEM>А это что за история?
Ну также как исключения, типа замедляет код делает его сложным и т.п.
В некоторых случаях уместно конечно но обычно это пустые слова.

CEM>PS: почему плохо кидать throw int?

Потому что баг в дизайне исключений
Имея один базовый класс мы можем делать просто catch(exception&) и получить данные.
А вот с int что делать будем ? Добавим catch на все возможные типы ? Не вариант конечно.
Поэтому делают в таких случаях catch(exception&) {} catch(...) {} .
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[9]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 09:52
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Это пример о пользе деструкторов, а не о пользе исключений.

Это конечно так, но без деструкторов не имеет смысла говорить об исключениях.
Исключения без деструкторов отменяют всю идею транзакционости.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[10]: C++ Best Practices
От: T4r4sB Россия  
Дата: 03.11.15 09:59
Оценка:
Здравствуйте, _NN_, Вы писали:

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


TB>>Это пример о пользе деструкторов, а не о пользе исключений.

_NN>Это конечно так, но без деструкторов не имеет смысла говорить об исключениях.
_NN>Исключения без деструкторов отменяют всю идею транзакционости.

А при деструкторах уже и исключения не так сильно нужны.
По мне, они действительно нужны для отлова ситуаций, которых, по мнению программиста, быть не должно. Как последний рубеж обороны от взрыва реактора. А для остального, имхо, минусы перевешивают плюсы.
Re[11]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 10:16
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>А при деструкторах уже и исключения не так сильно нужны.

TB>По мне, они действительно нужны для отлова ситуаций, которых, по мнению программиста, быть не должно. Как последний рубеж обороны от взрыва реактора. А для остального, имхо, минусы перевешивают плюсы.
Как вы будете проверять вызов конструктора ? Конвенция функции bool Init(...) ?
Тут получается нужно писать код для правильной обработки этих ситуаций , что значит легко ошибиться.
Кроме того таким образом не получится создавать константные члены класса.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[10]: C++ Best Practices
От: CEMb  
Дата: 03.11.15 10:19
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>Количество задействованных if-ов можете подсчитать сами...


Это да, но:

1. если так, то по нормальному, в ситуации, приближенной к жизни, мне в каждом методе надо будет кидать свой exception, который потом разбирать в if-ах что бы в TopMethod-e понять, что же там произошло внутри. В случае с if-ами я могу возвращать код и по нему понимать. В случае с try/catch я могу (и так вроде правильнее) использовать разные классы исключений, что формально исключает if-hell но по сути, тот же самый разбор по catch-ам:
// :)
#define If catch

и да, в этом случае, если raii, код в последнем методе будет выглядеть как switch/case, если классы исключений в одной иерархии.
ну и в случае true/false приведённый пример полностью демонстрирует преимущество, согласен, но в жизни мне такие методы редко попадались

2. опять же в жизни, где в методах много "другого" кода, в случае if-ов я знаю, что вызов функции закончится там, где она вызвана, там же будет обработка возвращённого кода(если по нормальному) или объекта(тогда вся обработка отлично инкапсулируется в его классе) т.е. я увижу всю логику кода по данной функции в одном месте. В случае try/catch мне придётся листать вниз, искать catch, причём этот catch может ловить не только выбросы из моего метода, т.е. там может быть некий "странный" код, за причинами которого придётся смотреть весь проект, где кидается данное исключение, и разбираться, по каким вызовам мы туда попали. Это очень похоже на goto, но в одну сторону и ограниченное по расстоянию, зато не ограниченное по скопу. Это всё про отладку и чтение кода речь.

0. и почему в качестве исключений плохо бросать целые числа? ну про попадание в if-hell понятно, но что-то ещё плохо?
Re[10]: C++ Best Practices
От: CEMb  
Дата: 03.11.15 10:39
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Во многих случаях неважно вылетело на первой строке или на второй, главное что не получилось

Во!

_NN>Можно конечно bool TryThis(..., string& errorString)

_NN>А если мы хотим больше чем строка ? скажем ip адрес высказать, что тогда ?
Ну, кстати, ровно как и с исключениями, сделать класс под ошибки и его возвращать или как с GetLastError() сделать глобальные функции, которые будут с любого места этот объект устанавливать/возвращать.

_NN>Ну также как исключения, типа замедляет код делает его сложным и т.п.

_NN>В некоторых случаях уместно конечно но обычно это пустые слова.
я смотрел асм, вроде по коду получается, что try/catch как раз работает быстро.
Re[8]: C++ Best Practices
От: B0FEE664  
Дата: 03.11.15 12:04
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>
_NN>com_ptr<IFileOpenDialog> pFileOpen(__uuidof(....)...); // не получится - исключение
_NN>pFileOpen.Show(NULL); // не получится - исключение
_NN>com_ptr<IShellItem> pItem(pFileOpen.GetResult()); // не получится - исключение

_NN>return pItem; // в коде выше вообще этого нет , придется передавать указатель на указатель и думать о Release. :-/
_NN>

_NN>Кому надо поставит try-catch в нужном месте.
Как этот кто-то узнает где и что ему нужно ловить? Откуда ему вообще знать, что функция может что-то выкинуть?
И каждый день — без права на ошибку...
Re[8]: C++ Best Practices
От: B0FEE664  
Дата: 03.11.15 12:09
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Это как от dynamic_cast и RTTI отказаться без обоснований.


dynamic_cast и RTTI не нужны за очень редкими исключениями.
И каждый день — без права на ошибку...
Re[12]: C++ Best Practices
От: T4r4sB Россия  
Дата: 03.11.15 13:05
Оценка: :)
Здравствуйте, _NN_, Вы писали:

_NN>Как вы будете проверять вызов конструктора ?


Сложный вопрос. Ещё более сложный вопрос — аналогичный про деструктор.
Re[9]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 13:07
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Как этот кто-то узнает где и что ему нужно ловить? Откуда ему вообще знать, что функция может что-то выкинуть?


Документация.
Тот же вопрос можно задать и про коды возврата, как знать 0 это успешно или ошибка ?
Можно конечно в стиле Java писать в сигнатуре, но опыт людей показал, что это не самая хорошая идея.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[10]: C++ Best Practices
От: B0FEE664  
Дата: 03.11.15 13:43
Оценка:
Здравствуйте, _NN_, Вы писали:

BFE>>Как этот кто-то узнает где и что ему нужно ловить? Откуда ему вообще знать, что функция может что-то выкинуть?

_NN>Документация.
Да? И кто будет писать эту документацию? А как же положение о том, что код должен быть самодокументирующим?

_NN>Тот же вопрос можно задать и про коды возврата, как знать 0 это успешно или ошибка ?

А и не надо ложных альтернатив. Возвращайте значение enum'а.
Автор: B0FEE664
Дата: 08.10.15
И каждый день — без права на ошибку...
Re[11]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 14:15
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

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


BFE>>>Как этот кто-то узнает где и что ему нужно ловить? Откуда ему вообще знать, что функция может что-то выкинуть?

_NN>>Документация.
BFE>Да? И кто будет писать эту документацию? А как же положение о том, что код должен быть самодокументирующим?
Хорошо берем С без исключений совсем.
Пользуемся

FILE* f = fopen(...); // как знать если была ошибка ? только читать документацию.
// Другой пример
HANDLE h = CreateFile(...); // что является ошибкой ? NULL ? INVALID_HANDLE_VALUE ? другое значение?


Коды ошибок не избавляют от чтения документации совсем.
Более того встает вопрос как понять в чём проблема ?
Изобретать свой NTSTATUS, HRESULT ? errno , GetLastError ? другие варианты ?
Или передавать объект который будет заполнятся в случае проблемы ?
В итоге получим тоже самое только с более усложнённым кодом.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[12]: C++ Best Practices
От: B0FEE664  
Дата: 03.11.15 15:19
Оценка:
Здравствуйте, _NN_, Вы писали:

BFE>>>>Как этот кто-то узнает где и что ему нужно ловить? Откуда ему вообще знать, что функция может что-то выкинуть?

_NN>>>Документация.
BFE>>Да? И кто будет писать эту документацию? А как же положение о том, что код должен быть самодокументирующим?
_NN>Хорошо берем С без исключений совсем.
Нет, я не согласен на C. Речь идёт о C++.

_NN>FILE* f = fopen(...); // как знать если была ошибка ? только читать документацию.

В данном случае мы знаем, что ошибка есть, если f == nullptr, но что это за ошибка — мы не знаем. Но это только потому, что указатель имеет специально выделенное значение.

_NN>// Другой пример

_NN>HANDLE h = CreateFile(...); // что является ошибкой ? NULL ? INVALID_HANDLE_VALUE ? другое значение?
Без документации невозможно этим воспользоваться, в отличии от функции бросающий исключение. Так что тут разницы нет.

_NN>Коды ошибок не избавляют от чтения документации совсем.

В этих примерах нет кодов ошибок.

_NN>Более того встает вопрос как понять в чём проблема ?

А как это понять с исключением? Взять error code из пойманного исключения? А в чём разница-то? Что вы пытаетесь продемонстрировать?

_NN>Изобретать свой NTSTATUS, HRESULT ? errno , GetLastError ? другие варианты ?

Тоже самое придётся делать и для исключения.

_NN>Или передавать объект который будет заполнятся в случае проблемы ?

Вернуть объект содержащий код ошибки.

_NN>В итоге получим тоже самое только с более усложнённым кодом.

В большинстве случаев, когда используют исключения обработкой ошибок вообще не занимаются. Если ошибки не обрабатывать, тогда — да, код проще.
И каждый день — без права на ошибку...
Re[13]: C++ Best Practices
От: _NN_ www.nemerleweb.com
Дата: 03.11.15 16:31
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

_NN>>В итоге получим тоже самое только с более усложнённым кодом.

BFE>В большинстве случаев, когда используют исключения обработкой ошибок вообще не занимаются. Если ошибки не обрабатывать, тогда — да, код проще.
Я думаю мы пришли к консенсусу.
На мой взгляд этот вариант самый распространённый.
Обычно есть последовательность 1,2,3,4 не важно что не получилось мы хотим откатиться и вывести ошибку.
В случае с исключениями выходит линейный и простой код.

Конечно если нужно каждый этап проверять отдельно тут что исключения что коды возврата потребуют дополнительный код.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.