Re: Исключения в C++
От: Mr.Delphist  
Дата: 24.03.16 12:18
Оценка: +1
Здравствуйте, Шахтер, Вы писали:

Ш>В отличии от оператора throw, error не прерывает исполнения, а сигнализирует об ошибке.

Логгер, своя функция и т.п. — сигнализируй не хочу.

Ш>Блок try/catch должен быть устроен так


Опять же, это решается перехватом исключения с подавлением или без подавления этого исключения. Если можем сами — отреагировали на ситуацию и подавили. Если не можем — реагируем на исключение и пробрасываем наверх либо само исключение, либо производное от него (например, оригинальное исключение кладём как дочернее поле в охватывающее исключение, оговоренное контрактом API).
Re[3]: Исключения в C++
От: Шахтер Интернет  
Дата: 24.03.16 13:54
Оценка:
Здравствуйте, enji, Вы писали:

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


K>>Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?


E>У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)


Можно делать вот так. Но тут тоже rethrow.

/* main.cpp */ 

#include <iostream>

using namespace std;

/* handle() */

void handle()
 {
  try
    {
     throw;
    }
  catch(int a)
    {
     cout << a << endl ;
    }
  catch(const char *str)
    {
     cout << str << endl ;
    }
 }

/* main() */

int main()
 {
  try
    {
//     throw 12345;
     throw "67890";
    } 
  catch(...)
    {
     handle(); 
    }

  return 0;
 }
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[6]: Исключения в C++
От: _hum_ Беларусь  
Дата: 24.03.16 16:27
Оценка: +1 :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Шахтер, Вы писали:


Ш>>А твой случай нужно разруливать не на исключениях, а на продолжениях.


E>Вот я и спрашиваю, зачем всё так усложнять?


это наверное частный случай более общего вопроса — зачем вообще понадобилось вводить исключения.
Re[7]: Исключения в C++
От: Erop Россия  
Дата: 24.03.16 16:38
Оценка: 1 (1)
Здравствуйте, _hum_, Вы писали:

__>это наверное частный случай более общего вопроса — зачем вообще понадобилось вводить исключения.

В данном случае вопрос скорее, зачем вводить продолжения

По исключениям вроде есть удачные практики использования, и там в деструкторах не кидают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Исключения в C++
От: antropolog  
Дата: 24.03.16 17:18
Оценка:
Здравствуйте, Шахтер, Вы писали:

Кстати, если добавить немного ада в виде оператора запятая, то будет местами похоже на то что тебе нужно, т.е. а-ля:

class catch_dispatcher {
public:
  template <typename T>
  void operator,(const T& obj) const {
    try{
     throw obj;
    }
    catch(...) {
      handle();
    }
  }

  void handle() const {
    try {
      throw;
    }
    catch(int a) {
      cout << "Error: " << a << endl;
    }
    catch(const char* str) {
      cout << "Error: " << str << endl;
    }
    catch(const std::exception& e) {
      cout << "Error: " << e.what() << endl;
    }
  }
};


А затем совсем наркомания:

#define throw_error catch_dispatcher(),

auto main(int argc, char argv[]) -> int try {
  throw_error 42;
  throw_error "Hello!";
  throw_error std::runtime_error("wow");
  throw_error std::string("Bad");
}
catch(...) {
  cout << "Unhandled exception" << endl;
}


Output:

Error: 42
Error: Hello!
Error: wow
Unhandled exception


для сильных духом мужчин:
s/throw_error/throw/g
Re[3]: Исключения в C++
От: Erop Россия  
Дата: 24.03.16 21:07
Оценка:
Здравствуйте, enji, Вы писали:

E>У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)


А почему перевыброс не быстро?
Что там медленного?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Исключения в C++
От: kov_serg Россия  
Дата: 24.03.16 22:38
Оценка: +1
Здравствуйте, Шахтер, Вы писали:

Ш>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.


Незнаю как вам. А мне не хватает функции замера и ограничения ресурсов.
Например вызвать метод c ограниченным временем исполнения,
ограничением на использования стека и динамической памяти.
И чтоб при завершении потока автоматом останавливались его дочерние потоки
и освободдались ресурсы которые они выделяли.
И чтоб это было из коробки.

И много еще чего нехватает. Более того некоторые вещи досих пор удивляют и вызывают недоумение.
Проблемма языков высокого уровня, в моём понимании это упростить написание программ, а не наоборот.
И еще как правило надо не просто решить задачу, а с учетоим каких-то ограничений.

наприер задача отсортировать милиард строк при ограничении по доп. памяти в 16Кб.
или в данном файле запрещено использовать шаблоны
или не использовать макросы
или ни каких fpu только хардкор и битовые операции
или другие соглашения, что б их проверял компилятор.

Но C++ не для этого. Он для вечного изучения и поддержания уже написанных костылей

Главная проблемма что на этих языках пишут люди. У всех людей мозг имеет особенности которые мы получили в результате эволюции
их никто не учитывает при написании языков программирования. В отличии от компьютеров
мозг имеет очень ограниченные возможности и имеет известные недостатки. Пока главным инструментом являлась письменность.
Короче: "Без карандаша с блокнотом, настоящего программиста не получится". Именно из-за особенностей мозга.
https://www.youtube.com/watch?v=D_pwT1L7NLU
https://www.youtube.com/watch?v=2PD383EtpRw
Re[8]: Исключения в C++
От: Evgeny.Panasyuk Россия  
Дата: 25.03.16 02:06
Оценка:
Здравствуйте, Erop, Вы писали:

EP>>Ты же задачу такую поставил, или нет? То есть нужно обработать и исправить ошибку где-то выше по логическому стэку компонентов, там где есть необходимая информация и полномочия, а потом продолжить на исходном низком уровне, так?

EP>>Сложность-то она в самой задаче, а не в решении.
E>Ну вот смотри, мы пишем ТРИ файла, флушим, получаем "места нет", и решаем, то надо спросить пользователя что делать. Пользователь говорит: "пиши док на другой диск". И как это случится?
E>А альтернативный вариант -- у нас всё пишется явно, а не в деструкторе, и вызывающий код всем рулит, пока оно ещё не разрушилось... Второе очевидно проще же?

А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе Тебе и там и там нужно передать управление в другой контекст, туда где знают как реагировать (например знают как нарисовать GUI диалог), и это основная сложность
Re[9]: Исключения в C++
От: Erop Россия  
Дата: 25.03.16 08:23
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе



1) Деструктор трудно отменить.
2) Если в запросе участвует несколько сущностей, то к моменту вызова деструктора одной из них, остальные могут быть уже разрушены.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Исключения в C++
От: _hum_ Беларусь  
Дата: 25.03.16 10:39
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе


E>1) Деструктор трудно отменить.


если речь о с++, то там, вроде бы, еще и проблема в том, что

wiki/Обработка исключений
[...]встречается возможность гарантированного завершения блока кода (finally, ensure). Заметным исключением является Си++, где такой конструкции нет. Вместо неё используется автоматический вызов деструкторов объектов.
[...]
Корректная реализация исключений может быть затруднительной в языках с автоматическим вызовом деструкторов. При возникновении исключения в блоке необходимо автоматически вызвать деструкторы объектов, созданных в данном блоке, но только тех, которые не были ещё удалены обычным порядком. Кроме того, требование прерывания текущей операции при возникновении исключения вступает в противоречие с требованием обязательного автоматического удаления в языках с автодеструкторами: если исключение возникнет в деструкторе, то либо компилятор будет вынужден удалить не полностью освобождённый объект, либо объект останется существующим, то есть возникнет утечка памяти. Вследствие этого генерация неперехватываемых исключений в деструкторах в ряде случаев просто запрещается.

Re[2]: Исключения в C++
От: _hum_ Беларусь  
Дата: 25.03.16 10:48
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, Шахтер, Вы писали:


Ш>>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.


_>Незнаю как вам. А мне не хватает функции замера и ограничения ресурсов.


полагаете, что все-таки рост объема обрабатываемых данных опередит рост производительности и емкости устройств?
просто это как бы возврат к уровню си — когда приходится значительное внимание уделять особенностям строения машины, на которой предполагается работа алгоритма...




глянул ваши ссылки на ютьюбе. странный там товарищ, попахивающий "лысенковщиной".
Re[10]: Исключения в C++
От: Evgeny.Panasyuk Россия  
Дата: 25.03.16 14:18
Оценка:
Здравствуйте, Erop, Вы писали:

EP>>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе

E>1) Деструктор трудно отменить.

Зачем тебе его отменять?

E>2) Если в запросе участвует несколько сущностей, то к моменту вызова деструктора одной из них, остальные могут быть уже разрушены.


Ты о чём вообще?

У тебя был код:
if(file_flush() == not_enough_space)
     fail();
Стал:
if(file_flush() == not_enough_space)
    if(call_not_enough_space_handler() == successfully_freed_space)
        file_flush();
    else
        fail();

Изменение только в том, что fail будет происходить реже. А вот где он был, и какой механизм использовался — это ортогонально данной дополнительной обработке
Re[11]: Исключения в C++
От: Erop Россия  
Дата: 25.03.16 16:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Зачем тебе его отменять?

Ну вот смотри, сценарий.
Я, такой красивый, нажал кнопочку "закрыть окно", окно закрывается, документ флушится на диск, и тут бабам! "МЕСТО ЗАКОНЧИЛОСЬ, ПРИМИТЕ МЕР!".
Я такой смотрю и понимаю, что уронил нечаянно голову на Ctrl+V и так поспал полчасика, и надо бы файло поредактировать мальца, перед тем, как окончательно записывать...
Ну я такой, в филесаве диалоге говорю "отменить", и? Что дальше происходит?

EP>У тебя был код:

EP>
EP>if(file_flush() == not_enough_space)
EP>     fail();
EP>
Стал:

EP>
EP>if(file_flush() == not_enough_space)
EP>    if(call_not_enough_space_handler() == successfully_freed_space)
EP>        file_flush();
EP>    else
EP>        fail();
EP>

EP>Изменение только в том, что fail будет происходить реже. А вот где он был, и какой механизм использовался — это ортогонально данной дополнительной обработке

А если хендлеру надо ПЕРЕМЕСТИТЬ этот файл на другой диск, тока в комплекте ещё с двумя другими. Но CFile одного из этих других уже разрушен?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Исключения в C++
От: ononim  
Дата: 26.03.16 13:36
Оценка: +1
немного не по теме но иногда хотелось бы чтобы можно было написать вместо try — retry
то есть бывает некая последовательность действий, которую можно выполнить несколько раз, но в ходе выполнения которой могли бы быть некие проблемы, которые можно починить в catch и перезапустить исходную последовательность
типа
void inner()
{
 some_vector.resize(some_value);
}

void outer()
{
 try
 {
  inner();
 }catch (bad_alloc &a)
 {
  free_some_memory();
  inner();//если исключение вылезет и отсюда - значицца у нас ничего не получилось :(
 }
}

можно было бы заменить на эквивалентное

void outer()
{
 retry 
 {
  some_vector.resize(some_value);
 }catch (bad_alloc &a)
 {
  free_some_memory();
 }
}

или как вариант параметризовать try количеством пере-попыток (по дефолту значицца оно равно нулю):
void outer()
{
 try(1)
 {
  some_vector.resize(some_value);
 }catch (bad_alloc &a)
 {
  free_some_memory();
 }
}
Как много веселых ребят, и все делают велосипед...
Отредактировано 26.03.2016 13:40 ononim . Предыдущая версия .
Re[2]: Исключения в C++
От: kov_serg Россия  
Дата: 26.03.16 17:16
Оценка:
Здравствуйте, ononim, Вы писали:

O>немного не по теме но иногда хотелось бы чтобы можно было написать вместо try — retry

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

Что мешает сделать примерно так?
...
struct Try { 
    int en,cnt;
    Try() { en=1; cnt=0; }
    operator int() { return en; }
    void handle() { 
        cnt++;
        try {
            throw;
        } catch(EMemory *e) {
            if (cnt==1) gc();
            if (cnt==2) { en=0; throw; }
            //...
        } catch(...) {
            en=0;
            throw;
        }
    }    
    void gc() { /*...*/ }
};

#define TRY for(Try t;t;) { try {
#define END } catch(...) { t.handle(); } }

...

TRY some_work(); END
Re[3]: Исключения в C++
От: ononim  
Дата: 26.03.16 18:00
Оценка:
моя задумка чтоб код получился попроще для написания и чтения, причем для разных вариантов кода в catch и разных исключений. Вариант с памятью — просто вариант. Могут быть куча других ситуаций типа:
 try(5)
 {
  host.resolve();
  host.connect();
 }catch (network_error &a)
 {
  sleep(1);
 }

или
 try(1)
 {
  read_config();
 }catch (config_broken &a)
 {
  restore_from_backup();
 }

И для каждого случая рисовать свою структуру? Тогда уж проще по старинке...
Как много веселых ребят, и все делают велосипед...
Отредактировано 26.03.2016 18:04 ononim . Предыдущая версия .
Re[4]: Исключения в C++
От: kov_serg Россия  
Дата: 26.03.16 18:42
Оценка:
Здравствуйте, ononim, Вы писали:

O>моя задумка чтоб код получился попроще для написания и чтения, причем для разных вариантов кода в catch и разных исключений. Вариант с памятью — просто вариант. Могут быть куча других ситуаций типа:


И что мешает. Это тоже прото эскиз:
struct Policy {
    static Policy* getContextPolicy();
    virtual void handle(int limit) {
        try {
            throw;
        } catch(EMemory *) {
            //...
        } catch(...) {
            //...
        }
    }
};

struct Try { 
    int limit;
    Policy *policy;
    Try(int count,Policy *policy) { limit=count; }
    operator int() { return limit>0; }
    void handle() { 
        if (limit-->0) policy->handle(limit);
        else throw;
    }    
    void gc() { /*...*/ }
};

#define TRY_LIMIT(n) for(Try t(n,Policy::getContextPolicy());t;) { try {
#define END } catch(...) { t.handle(); } }

...
TRY_LIMIT(3) some_work(); END


O>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке...

Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма.
Re[5]: Исключения в C++
От: ononim  
Дата: 26.03.16 19:02
Оценка:
O>>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке...
_>Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма.
Вариантов тьма. А вот варинтов таких, чтобы нуб придя на проект в течении секунд 20 врубился что делает код сейчас ровно один:
try
{
work();
}catch
{
repair();
work();
}

Ваши примеры к таким не относятся. Кроме того последний вариант требует "заточки" под себя кода, который он обслуживает, что опять же ухудшает понимабельность и рефакторабельность кода.
Как много веселых ребят, и все делают велосипед...
Re[6]: Исключения в C++
От: kov_serg Россия  
Дата: 26.03.16 19:52
Оценка:
Здравствуйте, ononim, Вы писали:

O>>>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке...

_>>Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма.
O>Вариантов тьма. А вот варинтов таких, чтобы нуб придя на проект в течении секунд 20 врубился что делает код сейчас ровно один:
O>
O>try
O>{
O>work();
O>}catch
O>{
O>repair();
O>work();
O>}
O>

O>Ваши примеры к таким не относятся. Кроме того последний вариант требует "заточки" под себя кода, который он обслуживает, что опять же ухудшает понимабельность и рефакторабельность кода.

Нет проблем. Только кому это надо?
struct ECritical {};
struct EIgnorable {};

struct Try {
    int stage,limit; 
    enum { Recover=0,Body=1,Success=2,Leave=3 };
    Try(int count) { stage=1;limit=count-1; }
    operator int() { return stage!=3; }
    void step() { if (stage==0) stage=1; stage++; }
    void handle() {
        if (stage<=1) {
            check_exception();
            if (limit>0) { limit--; stage=-1; }
            else throw;
        } else {
            throw;
        }        
    }
    void check_exception() {
        try { throw; } 
        catch(ECritical) { throw; }
        catch(EIgnorable) { } 
        catch(...) { /*unexprected*/ throw; }
    }
};

#define TRY_LIMIT(n) try{for(Try t(n);t;t.step()) { try { switch(t.stage) {
#define RECOVER      case 0:
#define BODY         case 1:
#define SUCCESS      break; case 2:
#define FAIL         }} catch(...) { t.handle(); }}} catch(...) {
#define END_REPEAT   }

...

int ok=0;

TRY_LIMIT(3)
RECOVER { gc(); }
BODY    { some_work(); }
SUCCESS { ok=1; }
FAIL    { ok=0; /*throw;*/ }
END_REPEAT
Re[7]: Исключения в C++
От: kov_serg Россия  
Дата: 26.03.16 20:00
Оценка:
даже так можно сделать.
TRY_LIMIT(3) {
RECOVER { gc(); }
BODY    { some_work(); }
SUCCESS { ok=1; }
FAIL    { ok=0; /*throw;*/ }
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.