Re[6]: Разработка на чистом C
От: push  
Дата: 31.10.16 12:47
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Ты представляешь сколько тактов занимает сравнение кода возврата в регистре с кодом успеха?

lpd>Для прикладного кода да, исключения подходят. Но иногда(например, real-time код) необходимо понимать их ограничения по скорости.

Ты про серебряную пулю?) Такого не бывает. С помощью С++ ясен пень можно и плохо сделать при желании. Исключения легко существуют с возвратом bool. Но как только количество кодов возврата превышает количество флагов (к примеру в char, int — или где хранятся) — производительность исключений вне вопросов.
А для real-time там своя специфика — но это не отменяет того, что стоимость использования исключений вне его можно принимать за ноль.
Re[5]: Разработка на чистом C
От: T4r4sB Россия  
Дата: 31.10.16 12:57
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Вы похоже ещё не видали C11 _Generic и C99 inline


Видел. Про генерики как раз вспоминал, когда писал свой пост.
Короче, любой язык со временем мутирует в сикрест.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: Разработка на чистом C
От: push  
Дата: 31.10.16 12:59
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Мля, Вы не понимаете, всё то, что Вы говорите, похоже на теоретическую воду. Причин отказа от фишек С++ могут быть сколько угодно. Вот у нас функция, инициализирующая ряд ресурсов, чтоб не писать простыню, пишем ряд функций для инициализации каждого ресурса и вызываем их по порядку. В каждой инициализация может окончиться ошибкой, но в этом случае не нужно откатываться куда-то дальше этой функции, а просто передать ей другие параметры и вызвать снова. Как ловить ошибку в каждой такой функции, считывать код возврата или кидать в ней исключение? Первое будет производительней, особенно если эта инициализирующая ресурсы функция вызывается несколько десятков тысяч раз в секунду, это, например, сервер, обрабатывающий запросы. Если использовать исключения, будем десятки тысяч раз в секунду нырять в throw. Оно надо? Лучше вернуть код возрата, тем более если там возврат может быть только true или false. Так же и с инициализацией, объекты создаются и уничтожаются тысячами в секунду, инициализировать их с init/create-и смотреть на возврат-простое эффективное решение, чем пихать всё в конструктор, проверяться исключениями, постоянно делать is_good, объекту.

S> Короче, теоретически C++-ные вещи выглядят красиво, но на практике, особенно если речь идёт об исполнении проги в агрессивных условиях исполнения, эти вещи часто превращается просто в уродство, и нужно, как бегущему легкоатлету нужно болтающееся конское седло между ног. Ядро ОС исполняется в агрессивной среде, агрессия идёт со стороны железа, прикладных прог, приходящих извне данных, там С++-ные фишки будут жутко мешать, они только всё усложняют, потому С++ в ядра с намордником не пускают

Вы пытаетесь показать, что с помощью С++ если постараться, то можно сделать плохо? Не нужно, все мы в курсе этого. Тут все ошибки в одном месте: успешность инициализации не зависит от объекта, ситуация не является исключительной (штатная, раз можно перезапустить функцию с другими параметрами при неудаче), неудача не содержит информации (true/false). Пытаться всё это завернуть в RAII — это как попытка натянуть сову на глобус. Это не RAII проблема.
Re[9]: Разработка на чистом C
От: smeeld  
Дата: 31.10.16 13:09
Оценка:
Здравствуйте, Pzz, Вы писали:


Pzz>Это, я полагаю, теоретическое построение, да?


Pzz>Symmetric cone NAT вряд ли выдержит десятки тысяч попыток установления соединения в секунду. Просто таблицы переполнятся, и дальше будет плохо. Собственно, обычные домашние роутеры зачастую не выдерживают и нескольких десятков попыток в минуту, просто зависают к чертовой матери.


Нет, у нас, например, редиректящий екстернальный сигнальный сервер, он получает соединение, и редиректит его другим хостам за натом, внешние адреса которых меняется постоянно, и он постоянно получает периодические уведомления о текущих адресах каждого хоста за натом, которые в состоянии online для некоторой p2p сети. Всё по TCP, понятно дело, ибо шифроваться нужно.
Re[11]: Разработка на чистом C
От: pestis  
Дата: 31.10.16 13:17
Оценка:
Здравствуйте, okman, Вы писали:

O>1. Работа такая.

O>2. Какое это имеет отношение к обсуждаемому вопросу?
O>3. Какое это имеет отношение к обсуждаемому вопросу?

Чтобы дать адресный совет, очевидно. Если ты наемный кодер, то тебе бесполезно советовать взять clojure и написать на нем адаптивный кодогенератор, менеджер заругает.

O>У меня набор callback-функций, предоставляемых операционной системой, которые

O>срабатывают при наступлении определенных событий. Открыли устройство — сработал один callback.
O>Закрыли — сработал другой. И т.д. В этих callback-функциях происходит создание различных
O>ресурсов, работа с ними и удаление. Управлять тем, чтобы ресурсы создавались где-то в одном
O>месте и в одном потоке, я не могу.

Можете, типичный паттерн registry. Потоки не выделяют ресурсы сами, а обращаются к registry и уже он выделяет ресурс и смотрит кому что выдано. После смерти потока/устройства/whatever registry проверяет выданные ресурсы и прибирает все что забыли удалить явно. Для этого достаточно только сдизайнить вменяемый life cycle ваших ресурсов и определить что для вас unit of work. Я надеюсь готовить ООП на чистом С вы умеете?

O>Review не дает гарантию, что все ссылки во всех ветках выполнения были освобождены.


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

O>Мечтаю увидеть, как пишутся драйверы и прочий системный низкоуровневый код на Python/Clojure/etc.


Пишутся, и еще как: готовится модель, описывается на любом языке с минимальным синтаксисом (Clojure, Scheme, Lisp, Ruby), из этой модели делается кодогенерация в С. Бывает что кодогенерацию делают прямо в реалтайме, с учетом внешнего окружения.
Re[11]: Разработка на чистом C
От: lpd Черногория  
Дата: 31.10.16 13:39
Оценка:
Здравствуйте, okman, Вы писали:

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


lpd>>shared_ptr неудобен и все равно нужно в некоторых местах использовать weak_ptr из-за кольцевых ссылок, что только усложняет дело.


O>Shared_ptr в любом случае лучше, чем управление ссылками "вручную".

O>А кольцевые ссылки — это проблема совсем другого уровня, чем утечка ссылок.

Во-первых, shared_ptr громоздок. Если современный C++-way состоит в том, чтобы везде использовать умные указатели и забыть про проблемы с памятью, то почему не сделать "Type ^ptr" или "smart Type *" для умного указателя вместо вырвиглазного шаблона shared_ptr<Type> ptr?
Во-вторых, забыть про проблемы не получится, т.к. по прежнему нужно вникать в детали управления памятью и использовать в ряде случаев weak_ptr. И именно эта проблема — основная, поскольку банально забыть free сложно, а диагностировать тривиальную утечку легко с помощью valgrind или аналогичных средств.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[12]: Разработка на чистом C
От: okman Беларусь https://searchinform.ru/
Дата: 31.10.16 14:02
Оценка:
Здравствуйте, pestis, Вы писали:

P>Если ты наемный кодер, то тебе бесполезно советовать взять clojure и написать на нем адаптивный кодогенератор, менеджер заругает.

P>...
P>готовится модель, описывается на любом языке с минимальным синтаксисом (Clojure, Scheme, Lisp, Ruby), из этой модели делается кодогенерация в С. Бывает что кодогенерацию делают прямо в реалтайме, с учетом внешнего окружения.

Т.е. предлагается решать проблемы C, используя Clojure, Scheme и другие языки?
Мне это не подходит, проще тогда сразу писать на них, а не на C.

P>Можете, типичный паттерн registry. Потоки не выделяют ресурсы сами, а обращаются к registry и уже он выделяет ресурс и смотрит кому что выдано. После смерти потока/устройства/whatever registry проверяет выданные ресурсы и прибирает все что забыли удалить явно. Для этого достаточно только сдизайнить вменяемый life cycle ваших ресурсов и определить что для вас unit of work. Я надеюсь готовить ООП на чистом С вы умеете?


Во-первых, при таком подходе все снова сведется к тому, что кто-то должен будет в нужных точках
вызывать нужные методы registry, чтобы тот подчищал выданные ресурсы. Получаем все ту же проблему,
только в несколько ином виде.

Во-вторых, время жизни объекта не всегда может совпадать со временем жизни потока, устройства или
чего-то еще. Доступ к объекту может потребоваться намного после того, как соответствующий файл
был закрыт (например, для сбора статистики).
Re[12]: Разработка на чистом C
От: okman Беларусь https://searchinform.ru/
Дата: 31.10.16 14:09
Оценка: +3
Здравствуйте, lpd, Вы писали:

lpd>Во-первых, shared_ptr громоздок.


Более громоздок, чем 100500 free/cleanup/delete по всему коду?

lpd>Во-вторых, забыть про проблемы не получится, т.к. по прежнему нужно вникать в детали управления памятью и использовать в ряде случаев weak_ptr. И именно эта проблема — основная...


Ну в моем примере, например, циклические ссылки невозможны, потому что объекты не
ссылаются друг на друга.

lpd>...поскольку банально забыть free сложно...

lpd>...а диагностировать тривиальную утечку легко с помощью valgrind или аналогичных средств.

Как все просто в этом мире, оказывается!
Re[13]: Разработка на чистом C
От: lpd Черногория  
Дата: 31.10.16 14:22
Оценка: :))) :)
Здравствуйте, okman, Вы писали:

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


lpd>>Во-первых, shared_ptr громоздок.


O>Более громоздок, чем 100500 free/cleanup/delete по всему коду?


Если delete написан явно, то это код читабельный и прозрачный. В случае shared_ptr все равно нужно учитывать время жизни объекта.
И не раскрыт вопрос, почему не сделали для него нормальный синтаксис.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[5]: Разработка на чистом C
От: Pavel Dvorkin Россия  
Дата: 31.10.16 14:46
Оценка:
Здравствуйте, _NN_, Вы писали:


PD>>Компилировать в Debug. Для Release Error code time будет просто 0, так как компилятор выкинет весь этот код с вызовом функции. Выкинуть код с исключением он не может.


PD>>Так что не надо заявлять, что обработка исключений столь уже дешева. Это все же вызов ядра (throw в VC++ вызывает RaiseException)

_NN>Давай правильно сравнивать.
_NN>Кинуть исключение дороже чем вернуть значение, с этим никто не спорит.
_NN>Однако, исключения это исключительная ситуация, а посему это должно быть редким явлением.

_NN>А теперь сравним именно такой код:



<skipped>

Ну писал же я чуть выше — компилировать в Debug, потому что Release просто выкинет код. Нет же, не верят. Ладно

Компилируем твой код в Release, ставим брекпойнт и смотрим disassembly

    dwTimeStart = GetTickCount();
0038102B  mov         ebx,dword ptr ds:[382000h]  
00381031  mov         edi,5F5E100h  
00381036  mov         dword ptr [count],edi  
00381039  call        ebx  
0038103B  mov         esi,eax  
    for (int i = 0; i < count; i++)
    {
        int result = ErrorCodeFunction(count);
    }
    dwTimeEnd = GetTickCount();
0038103D  call        ebx  

    printf("Error code time = %d\n", dwTimeEnd - dwTimeStart);
0038103F  sub         eax,esi  
00381041  push        eax  
00381042  push        382118h  
00381047  call        dword ptr ds:[382098h]  
0038104D  add         esp,8


call ebx — это и есть вызов GetTickCount. А между этими двумя вызовами стоит одна команда mov esi,eax. Вот ее время выполнения ты и замерил



_NN>Release:

_NN>Error code time = 0
_NN>Try catch time = 0


_NN>Увеличим количество итераций: int count = 100*1000*1000;

_NN>Release:
_NN>Error code time = 47
_NN>Try catch time = 62

А вот здесь у меня соответственно 0 и 217. Время выполнения команды команды mov esi,eax не изменилось

_NN>Получаем разницу 15ms/10*1000*1000 = 1.5ns.


Увы, но у меня будет 217/0

VS 2013
With best regards
Pavel Dvorkin
Re[5]: Разработка на чистом C
От: Pavel Dvorkin Россия  
Дата: 31.10.16 15:04
Оценка:
Здравствуйте, push, Вы писали:

P>Вы либо пытаетесь ввести в заблуждение, либо не до конца понимаете оптимизацию в с++. Тут даже без компиляции очевидно, что код с ErrorCodeFunction вырезается (и это абсолютно никак не связано с кодами возврата). В реальной функции ничего не вырезается.


Вырезается только в Release, о чем я ясно написал. Цитирую себя

PD>Компилировать в Debug. Для Release Error code time будет просто 0, так как компилятор выкинет весь этот код с вызовом функции. Выкинуть код с исключением он не может.


Поэтому я и проводил сравнения в Debug, где ничго не вырезается. Для чистоты эксперимента.

Вот disassembly кода в Debug

    for (int i = 0; i < count; i++)
0021159A  mov         dword ptr [ebp-3Ch],0  
002115A1  jmp         wmain+6Ch (02115ACh)  
002115A3  mov         eax,dword ptr [ebp-3Ch]  
002115A6  add         eax,1  
002115A9  mov         dword ptr [ebp-3Ch],eax  
002115AC  mov         eax,dword ptr [ebp-3Ch]  
002115AF  cmp         eax,dword ptr [count]  
002115B2  jge         wmain+85h (02115C5h)  
    {
        int result = ErrorCodeFunction(count);
002115B4  mov         eax,dword ptr [count]  
002115B7  push        eax  
002115B8  call        ErrorCodeFunction (02111D1h)  
002115BD  add         esp,4  
002115C0  mov         dword ptr [ebp-48h],eax  
    }
002115C3  jmp         wmain+63h (02115A3h)


P>В случае кодов возврата вам требуется проверять код каждый раз и для каждой функции, и вне зависимости от успеха/неудачи.


Верно. Но это всего лишь одна-две команды, что по сравнению с набором команд самой функции не очень большой оверхед, если функция мало-мальски сложная. Стоит функцию чуть-чуть изменить — и мы получим на десяток или сотню команд больше или меньше. Я уж не говорю, что будет, если в функции есть хотя бы линейный цикл — в этом случае это время сравнения есть просто O(1) на фоне O(N).

Есть и еще один момент. Коды возврата можно и не анализировать, если в данной ситуации он несущественен. Например, булевская функция delete может возвращать true, если удалили и false — если нет того, что нужно удалить. Но если мне все равно (а мне может быть все равно, так как мне надо, чтобы удаляемого там больше не было, и мне не важно, нет его теперь там потому, что удалили или потому, что и не было до попытки удалить), то я могу и игнорировать код возврата. Исключение не проигнорируешь.


P>Учитывая, что количество неудач по сравнению с количеством успешного выполнения функций ничтожно мало — то и накладные расходы на исключения фактически можно считать равными нулю. И нулю не только по сравнению с кодами возврата, а вообще в принципе. Потому что, при успехе накладных расходов почти нет, а при неудаче важность потребления процессорного времени по сравнению с важностью обработки ошибки стремиться к нулю.


А вот с этим могу согласиться. Действительно, пример мой довольно искусственный — так реально не бывает. Но я лишь хотел показать, что выброс исключения сравнительно недешевая вещь. Если оно и впрямь происходит очень-очень редко, то оверхедом на него можно пренебречь. Впрочем, это верно для чего угодно при условии, что это что угодно происходит очень-очень редко (и, конечно, само не занимает много времени). Если же не очень редко — тут все будет иначе.

Я не противник исключений, отнюдь нет. Я просто хотел напомнить, что это довольно затратный механизм и об этом надо помнить.
With best regards
Pavel Dvorkin
Отредактировано 31.10.2016 15:07 Pavel Dvorkin . Предыдущая версия .
Re[6]: Разработка на чистом C
От: _NN_  
Дата: 31.10.16 15:34
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

Ок более приближённый тест функция верхнего уровня не оптимизируется , скажем это функция обратного вызова.
#include <windows.h>

int ErrorCodeFunction(int count)
{
    if (count < -1) return 0;
    return count > 100 ? 1 : 2;
}

int CallErrorCodeFunction(int count)
{
    int r= ErrorCodeFunction(count);
    if (r == 0)
    {
        return 0;
    }
    else
        return r;
}

int ThrowFunction(int count) {
    if (count < -1) throw 1;
    return count > 100 ? 1 : 2;
}

int CallThrowFunction(int count)
{
    return ThrowFunction(count);
}

__declspec(noinline) int TestErrorCode(int result, int count)
{
    CallErrorCodeFunction(count);
    return result + 1;
}

__declspec(noinline) int TestThrow(int result, int count)
{
    try {
        ThrowFunction(count);

        return result + 1;
    }
    catch (...) {}
}

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwTimeStart, dwTimeEnd;

    int count = 100 * 1000 * 1000;

    int result=100;
    dwTimeStart = GetTickCount();
    for (int i = 0; i < count; i++)
    {
        result = TestErrorCode(result, count);
    }
    dwTimeEnd = GetTickCount();

    printf("Error code time = %d\n", dwTimeEnd - dwTimeStart);

    dwTimeStart = GetTickCount();
    for (int i = 0; i < count; i++)
    {
        result = TestThrow(result, count);
    }
    dwTimeEnd = GetTickCount();

    printf("Try catch time = %d\n", dwTimeEnd - dwTimeStart);

    return 0;
}


Тогда расклад:
Error code time = 125
Try catch time = 141

Debug: для 10*1000*1000
Error code time = 687
Try catch time = 469

VS2015Update3
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Разработка на чистом C
От: Pavel Dvorkin Россия  
Дата: 31.10.16 16:16
Оценка:
Здравствуйте, _NN_, Вы писали:

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


_NN>Ок более приближённый тест функция верхнего уровня не оптимизируется , скажем это функция обратного вызова.


<skipped>

Что-то я этот код плохо понимаю

1. CallThrowFunction нигде не вызывается и никому не нужна
2. TestErrorCode вызывает CallErrorCodeFunction, но не анализирует результат. Поэтому имеем следующее. Вот цикл



    for (int i = 0; i < count; i++)
    {
        result = TestErrorCode(result, count);
01081030  mov         ecx,esi  
01081032  call        TestErrorCode (01081000h)  
01081037  mov         esi,eax  
01081039  dec         edx  
0108103A  jne         wmain+20h (01081030h)  
    }


Все верно, TestErrorCode вызывется count раз

А теперь смотрим код TestErrorCode

Упс!

--- c:\users\dvorkin\documents\visual studio 2013\projects\consoleapplication8\consoleapplication8.cpp 
    CallErrorCodeFunction(count);
    return result + 1;
01081000  lea         eax,[ecx+1]  
}
01081003  ret


Так что ты просто время почти пустого цикла померил.

А теперь смотрим второй цикл

    for (int i = 0; i < count; i++)
    {
        result = TestThrow(result, count);
01081060  mov         ecx,esi  
01081062  call        TestErrorCode (01081000h)  
01081067  mov         esi,eax  
01081069  dec         edx  
0108106A  jne         wmain+50h (01081060h)  
    }


Вот тебе и раз. Компилятор почему-то решил, что здесь можно TestErrorCode вызвать вместо TestThrow. Но это не ошибка компилятора — если в TestThrow вставить printf, вызывается, как положено, TestThrow. Видимо, оптимизатор решил, что можно и ту вызвать, все равно. Может быть, потому что ErrorCodeFunction и ThrowFunction совпадают.

А пока что ты еще раз время почти пустого цикла померил. Времена совпадают

Кстати, если убрать __declspec(noinline), то оба времени равны 0, так как компилятор вообще оба цикла выбрасывает вместе со всем содержимым.

Непростая штука это оптимизатор, очень непростая

Ну а если по существу... Конечно, в зависимости от 1) как часто выполняется throw и 2) как соотносится количество команд на проверку кода возврата с количество команд в самой функции — соотношение может варьироваться в широких пределах.
Если сама функция содержит десяток команд, то дополнительные команды проверки кода возврата могут повлиять на скорость работы. Если же функция читает что-то с диска или из сети, то время для проверки кода возврата есть бесконечно малое по сравнению с временем работы функции.
Если throw происходит один раз на 100500 вызовов — его время есть бесконечно малое по сравнению с суммарным временем работы этих 100500 вызовов. Если каждые 5 раз — то может быть и сравнимо.

Так что истина конкретна.

А я всего лишь хотел показать, что собственно throw — try- catch достаточно затратная операция. А дальше — зависит от того, на фоне каких других затрат.
With best regards
Pavel Dvorkin
Отредактировано 31.10.2016 16:17 Pavel Dvorkin . Предыдущая версия .
Re[5]: Разработка на чистом C
От: antropolog  
Дата: 31.10.16 16:48
Оценка: 4 (1) :)
Здравствуйте, push, Вы писали:

P>Зачем делать откат на самые начала? Зачем ловить исключение сразу после вызова функции?....


Я бы мог пройтись практически по каждому пункту твоего поста, и показать что исключения сосут у кодов возврата. Но для лулзов просто поинтересуюсь, как дела с исключениям в асинхронных коллбеках? Как там, весело выше по стеку их хендлить?

Есть ещё один момент, когда доходит дела до деталей, то оказывается что не все исключения одинаково полезны. И (цитата) "исключения необходимо бросать только в исключительных ситуациях!" Поэтому, внимание! Сейчас совсем вводящий "исключительных" программистов в ступор вопрос: как определить что ситуация "исключительная"? Ну и контрольный! Должен ли метод OpenFile бросать исключение если файл не найден? (это просто пуля, голоса "исключительных" разделились ровно поровну, началась междуусобица, разброд и шатание)

  почти оффтоп
а то получается как у аджайловедов и прочих теоретиков кайфа —
----аджайл-пропоганда
Команда: А так можно делать?
Аджайл-балабол: Можно!
Команда: Но это же не совсем по аджайлу
Аджайл-балабол: В том то и дело, это же аджайл! Гибкая методология!
...
Команда: Мы тут делали аджайл и у нас не получилось
Аджайл-балабол: Вы просто не точно следовали практикам аджайла!

------исключительная пропаганда
Команда: А правда что с исключениями код будет лучше?
"Исключительный": Правда-правда. Только лучше и ничего кроме лучше!
Команда: У нас тут код с исключениями хуже чем с исключениями
"Исключительный": Ахххахаха /лалка/, тут же ситуация не-ис-клю-чи-тель-на-я !!!))))
Re[6]: Разработка на чистом C
От: push  
Дата: 31.10.16 18:12
Оценка: +2
Здравствуйте, antropolog, Вы писали:

A>Я бы мог пройтись практически по каждому пункту твоего поста, и показать что исключения сосут у кодов возврата.

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

A>Но для лулзов просто поинтересуюсь, как дела с исключениям в асинхронных коллбеках? Как там, весело выше по стеку их хендлить?

Оууу, а информация о исключении нужна там? (ну то есть если не исключение, то кода возврата ты будешь выдавать выше по стеку? ) То то же и оно. Я так понимаю начинаем придумывать как сделать плохо с помощью С++? Да можно-можно, никто и не спорит, если надо что-то запороть — то при старании получится.

A>Есть ещё один момент, когда доходит дела до деталей, то оказывается что не все исключения одинаково полезны. И (цитата) "исключения необходимо бросать только в исключительных ситуациях!" Поэтому, внимание! Сейчас совсем вводящий "исключительных" программистов в ступор вопрос: как определить что ситуация "исключительная"?

Элементарно Ватсон!) Исключительная ситуация, это когда выполняются все следующие пункты:
1) её возникновение не ожидается в (нормальном) потоке выполнения
2) делает невозможным выполнение целого блока кода
3) несёт информацию о проблеме (возврат true/false — не исключительная ситуация)

A>Ну и контрольный! Должен ли метод OpenFile бросать исключение если файл не найден?

Естественно должен. Почему смотри выше. Какие исключения могут быть — смотри сюда, в один из самых лучших фреймворков:
https://msdn.microsoft.com/en-us/library/b9skfh7s(v=vs.110).aspx
не плюсы, конечно, но сути не меняет.
Уж надеюсь ты не планировал сделать код возврата булевым, чтобы запороть всю инфу по проблеме?
Re[6]: Разработка на чистом C
От: push  
Дата: 31.10.16 18:22
Оценка: +1
Здравствуйте, antropolog, Вы писали:

A>Должен ли метод OpenFile бросать исключение если файл не найден? (это просто пуля, голоса "исключительных" разделились ровно поровну, началась междуусобица, разброд и шатание)

Разброд и шатание может быть только у джунов. И только потому, что они не видят что вопрос некорректный. Вопрос должен звучать так "Должен ли метод OpenFile бросать исключение?". И всё сразу становится на свои места.
Re[7]: Разработка на чистом C
От: antropolog  
Дата: 31.10.16 18:44
Оценка:
Здравствуйте, push, Вы писали:

P>C удовольствием послушаю.

Я думаю в процессе обсуждения все аргументы так или иначе будут озвучены.

P>Оууу, а информация о исключении нужна там? (ну то есть если не исключение, то кода возврата ты будешь выдавать выше по стеку? )


Я код возврата выдам напрямую в параметр коллбека. А вот что будешь ты делать с исключением — пока загадка.

P>Я так понимаю начинаем придумывать как сделать плохо с помощью С++?


причём здесь C++? Я тебе говорю об асинхронных коллбеках, т.е. коллбеках которые вызываются из другого контекста ( другой тред, очередной цикл event-loop ). Ты не сможешь поставить try catch вокруг вызова, потому что он асинхронный. Это же очевидно. Где тогда ловить исключение?

P>Элементарно Ватсон!) Исключительная ситуация, это когда выполняются все следующие пункты:

P>1) её возникновение не ожидается в (нормальном) потоке выполнения
P>2) делает невозможным выполнение целого блока кода
P>3) несёт информацию о проблеме (возврат true/false — не исключительная ситуация)

A>>Ну и контрольный! Должен ли метод OpenFile бросать исключение если файл не найден?

P>Естественно должен. Почему смотри выше.

Великолепно. Осталось только узнать, как OpenFile понимает, ожидается ли возникновение ошибки клиентским кодом или не ожидается? Что если таки ожидается и я в случае ошибки беру данные из другого файла/сети/whatever? Это нормальный flow, всё ожидаемо. Но вот почему-то OpenFile бросает исключение. Почему? Почему он делает мне неудобно?

P>Уж надеюсь ты не планировал сделать код возврата булевым, чтобы запороть всю инфу по проблеме?


А никакой инфы и нет. Более того, при использовании исключений этой инфы меньше в разы всегда. Просто открой любые C++ проекты и посмотри что там ловят в catch() и что при этом делают. И на это есть объективные причины.
Re[8]: Разработка на чистом C
От: push  
Дата: 31.10.16 19:27
Оценка:
Здравствуйте, antropolog, Вы писали:

A>Я код возврата выдам напрямую в параметр коллбека. А вот что будешь ты делать с исключением — пока загадка.

Код возврата чего? Ты же сказал, что даешь свой коллбек асинхронному фреймворку — ну у тебя возникла проблема и куда что возвращаешь?

P>>Я так понимаю начинаем придумывать как сделать плохо с помощью С++?


A>коллбеках которые вызываются из другого контекста ( другой тред, очередной цикл event-loop ).

std::promise/std::future

A>Великолепно. Осталось только узнать, как OpenFile понимает, ожидается ли возникновение ошибки клиентским кодом или не ожидается?

Это с какой такой радости он должен что-то понимать??? Такое в принципе невозможно. Он сигнализирует о проблеме, а дальше это уже проблема клиента как реагировать.

A>Что если таки ожидается и я в случае ошибки беру данные из другого файла/сети/whatever?

Ну и бери. И что?

A>Что если таки ожидается и я в случае ошибки беру данные из другого файла/сети/whatever? Это нормальный flow, всё ожидаемо.

Если в твоей проге это нормальный flow — то не бросай исключение. Я даже не буду спрашивать как так у тебя получилось, что ты хочешь взять данные из отсутствующего файла . Я же не в курсе, может у тебя всё автоматом подставляется, если нет прав — игнорируется, если нет файла — подставляется заглушка — тогда конечно, вообще и в принципе проверка наличия файла бессмысленная. Но такая логика программы всецело на твоей совести.
А в общем случае — отсутствие файла это исключение, так как его наличие должно было быть обеспечено раньше (да, в разработке принято проверять наличие чего-либо, прежде чем использовать).

A>Но вот почему-то OpenFile бросает исключение. Почему? Почему он делает мне неудобно?

Чем именно неудобно — что сказал правду об отсутствии файла?

A>А никакой инфы и нет. Более того, при использовании исключений этой инфы меньше в разы всегда. Просто открой любые C++ проекты и посмотри что там ловят в catch() и что при этом делают. И на это есть объективные причины.

Я вообще-то разрабатываю на плюсах и знаю как и что. С помощью исключений можно получить без напряга столько инфы, сколько при ручном сборе с помощью кодов возврата никогда не будет (ибо банально слишком трудоёмко). Открой для себя boost::exception. По пути раскрутки стека можно собрать практически дамп всех слоёв приложения.
Re[9]: Разработка на чистом C
От: lpd Черногория  
Дата: 31.10.16 19:38
Оценка: +1
Здравствуйте, push, Вы писали:

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


A>>А никакой инфы и нет. Более того, при использовании исключений этой инфы меньше в разы всегда. Просто открой любые C++ проекты и посмотри что там ловят в catch() и что при этом делают. И на это есть объективные причины.

P>Я вообще-то разрабатываю на плюсах и знаю как и что. С помощью исключений можно получить без напряга столько инфы, сколько при ручном сборе с помощью кодов возврата никогда не будет (ибо банально слишком трудоёмко). Открой для себя boost::exception. По пути раскрутки стека можно собрать практически дамп всех слоёв приложения.

У механизма исклюений есть как плюсы так и минусы. Одними из минусов кроме быстродействия являются усложнение логики(и уменьшение прозрачности кода) и увеличение связности программы — когда вызывающий код должен понимать и обрабатывать данные exceptionа из вызываемого.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[8]: Разработка на чистом C
От: _NN_  
Дата: 31.10.16 19:54
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А я всего лишь хотел показать, что собственно throw — try- catch достаточно затратная операция. А дальше — зависит от того, на фоне каких других затрат.

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