C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:06
Оценка:
Какие идиомы следует использовать, если нельзя использовать исключения?

Я пока остановился на вводе метода bool init(..args...),
который проводит инициализацию и возвращает флаг успешности инициализации.
В случае если init() вернул false, объект надо удалить.

class Foo : Base
{
public:
    Foo() : rawPtr(NULL) {} 

    bool init()
    {
       if (!Base::init("some arg"))
          return false;

       if (!mem1.init())
          return g_log.write("Foo::init : can't init mem1"), false;

       mem2.reset(CreateSome());
       if (!mem2)
          return g_log.write("Foo::init : can't create mem2"), false;

       rawPtr = CreateBar();
       if (rawPtr == NULL)
          return false;

       return true;
    }

    ~Foo()
    {
        if (rawPtr == NULL)
           FreeBar(rawPtr);
    }

private:
    SomeDefaultConstructible mem1;
    smart_handle mem2;
    Bar* rawPtr;
};

template<class C>
inline C* create()
{
    if (C* obj = new(std::nothrow) C())
    {
        if (obj->init())
        {
            return obj;
        }
        delete obj;
    }
    return NULL;
}


У такого подхода даже есть преимущество над конструкторами — в init() можно вызывать виртуальные методы.

Однако, я не уверен что это действительно хорошее решение, может есть лучше.

Также мне непонятно что делать с объектами создаваемыми на стеке.
Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.
Это сразу же убивает автоматический вызов деструкторов,
к тому же иногда надо будет дополнительно вводить код для предотвращения двойной деинициализации.
In Zen We Trust
Re: C++ без эксепшенов
От: uzhas Ниоткуда  
Дата: 28.07.11 18:11
Оценка: 9 (1)
Здравствуйте, Abyx, Вы писали:

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


A>Я пока остановился на вводе метода bool init(..args...),

приемлемый подход, минусы вы и сами видите
могу посоветовать еще подход bool IsValid()
в обоих случаях надобности в методе free не вижу
Re: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 18:16
Оценка:
A>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.
A>Это сразу же убивает автоматический вызов деструкторов,
Непонятно, зачем — вполне достаточно проверять флаг в самом деструкторе. А почему, если не секрет, исключения исключены (пардон за тавтологию)?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:19
Оценка:
Здравствуйте, uzhas, Вы писали:

U>в обоих случаях надобности в методе free не вижу


а ведь действительно, если объект создается на стеке, в случае провала init() можно сразу же сделать return и он удалится

что-то не представляю где может потребоваться вызов free()
In Zen We Trust
Re[2]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 18:28
Оценка:
Здравствуйте, Vamp, Вы писали:

A>>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.

A>>Это сразу же убивает автоматический вызов деструкторов,
V>Непонятно, зачем — вполне достаточно проверять флаг в самом деструкторе. А почему, если не секрет, исключения исключены (пардон за тавтологию)?

дай угадаю:
— более простой контроль на флоу?
— исключениефобия?
— эмбеддед система, но по сути тоже исключениефобия (см. technical report on c++ performance).
— не поддерживает компилятор?
Re[3]: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 18:31
Оценка: 6 (1) -3
I>- более простой контроль на флоу?
I>- исключениефобия?
Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:34
Оценка:
Здравствуйте, Vamp, Вы писали:

A>>Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить состояние объекта если init() провалился.

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

имелся ввиду код типа

Foo foo;
if (!foo.init())
{
   foo.free();
   MessageBox("Foo::init failed");
   return;
}

foo.use();


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

Foo foo;
if (!foo.init()) return;



V>А почему, если не секрет, исключения исключены (пардон за тавтологию)?

потому что проект собирается с -fno-exceptions
наверное потому что проект для embedded, а исключения вроде как раздувают бинарник (таблицами)
на самом деле я не знаю, просто такое требование %)

Вот в llvm например тоже запрещены исключения, потому что ллвм это библиотека, и разработчики не хотят чтобы использование ллвм мешало компилить код с -fno-exceptions, потому что "you only pay for what you use". Так что разные могут быть причины.
In Zen We Trust
Re[4]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 18:41
Оценка:
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

признаюсь, я тоже не фанат. но готовить умею)
Re[5]: C++ без эксепшенов
От: uzhas Ниоткуда  
Дата: 28.07.11 18:45
Оценка: +2
Здравствуйте, ilnar, Вы писали:

I>признаюсь, я тоже не фанат. но готовить умею)

а я фанат
ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на ковередж (юнит-тестами замучаешься все decisions покрывать)
хорошо, когда if находится в классе, а не у каждого клиента этого класса
Re[4]: C++ без эксепшенов
От: Abyx Россия  
Дата: 28.07.11 18:45
Оценка:
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

исключения нужны для возврата ошибки из конструктора
struct Foo
{
   Foo()
    : bar() // may throw
    , baz() // may throw
   {}

   Bar bar;
   Baz baz; 
};


и для возврата ошибки из функции которая иначе не может вернуть ошибку
int x = lexical_cast<int>("...");


в обоих случая варианты без исключений существенно снижают читаемость и надежность кода — исключения приходится заменять на член класса (isValid, whatHappened) или глобальную thread-local переменную.
In Zen We Trust
Re[5]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 19:00
Оценка:
Здравствуйте, Abyx, Вы писали:

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


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

A>исключения нужны для возврата ошибки из конструктора

Vamp просто не фанат, но "с творчеством знаком", будь уверен
Re[5]: C++ без эксепшенов
От: Vamp Россия  
Дата: 28.07.11 19:00
Оценка:
A>исключения нужны для возврата ошибки из конструктора
Дело не в этом. Дело в том, что ты делаешь потом.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: C++ без эксепшенов
От: ilnar Россия  
Дата: 28.07.11 19:01
Оценка:
Здравствуйте, Abyx, Вы писали:

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


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

A>исключения нужны для возврата ошибки из конструктора

овпрос был в другом, почему не хотите исключений?
Re[4]: C++ без эксепшенов
От: мыщъх США http://nezumi-lab.org
Дата: 28.07.11 20:14
Оценка: -1
Здравствуйте, Vamp, Вы писали:

I>>- более простой контроль на флоу?

I>>- исключениефобия?
V>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

это да. на плюсах нет возможности корректно обработать исключение. скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:04
Оценка: +1
On 28.07.2011 22:06, Abyx wrote:

> У такого подхода даже есть преимущество над конструкторами — в init() можно

> вызывать виртуальные методы.

Преимуществ нет. В конструкторе тоже можно вызывать виртуальные методы.
Лучше поборись за использование исключений.

>

> Однако, я не уверен что это действительно хорошее решение, может есть лучше.

Использовать исключения.

> Также мне непонятно что делать с объектами создаваемыми на стеке.

> Видимо надо дополнительно вводить еще и метод free(), чтобы сразу откатить
> состояние объекта если init() провалился.

Ничего окромя

if( doAll() != doneWell )
return;

не придумаешь. И именно с этим борятся исключения.

> Это сразу же убивает автоматический вызов деструкторов,

> к тому же иногда надо будет дополнительно вводить код для предотвращения двойной
> деинициализации.

ага, тогда давай на С сразу пиши. Нафига тебе С++ ?
Без иключений нельзя использовать STL, потому что оно их кидает.
Любая НОРМАЛЬНАЯ библиотека будет тоже на исключениях.
Так что тебе останется только С-шные либы исползовать,
и свой протокол инициализации и деструкторизации придумывать.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:11
Оценка: +1
On 28.07.2011 22:31, Vamp wrote:

> Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем

> так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все,

Ну, почти правильно думашь, и почти так оно и должно быть в ХОРОШЕЙ программе
на С++.

> что бросило исключение — проваливается в самый низ, логгируется и программа

> завершается.

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

> Если программа может продолжаться — то это не исключение, а возврат ошибки из

> функции.

Нет. Путаешь. Если прогамма может продолжить работу, выбрав и уничтожив
стек вызовов и всё, что там есть, -- это одно. А если ПОТОК ВЫПОЛНЕНИЯ программы
не может течь далее в рамках его нормальных ветвей (а других в общем и не
бывает), то это вот как раз то самое место, где кидается исключение.
В общем случае это совершенно разные вещи.

Ты всегда можешь сказать программе: "А давай-ка попробуем сделать вот это,
вдруг получится", и если не получится, то привести программу в состояние,
как будто бы ничего и не было.

> Но если объект критически важен, и его несоздание должно вызывать исключение —

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

Правильно считаешь.
Posted via RSDN NNTP Server 2.1 beta
Re[6]: C++ без эксепшенов
От: MasterZiv СССР  
Дата: 28.07.11 22:16
Оценка: +1 -1
On 28.07.2011 22:45, uzhas wrote:

> а я фанат

> ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на
> ковередж (юнит-тестами замучаешься все decisions покрывать)
> хорошо, когда if находится в классе, а не у каждого клиента этого класса

Главное даже не if-ы, а корректность программы.

Вот протокол (сигнатура) метода:

class Complex
{
...
Complex divide( const Complex& r ) const;
...
};


Ну и что ему возвращать при таком вызове:

Complex res = Complex( 2, 3 ).divide( 0 );

?

Если что-то возвращать, программа просто тупо становится
некорректной. А если вводить "флаги успешности выполнения
операции" -- сразу становится неуклюжей и неестественной.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: C++ без эксепшенов
От: Arsenicum Россия  
Дата: 29.07.11 07:53
Оценка:
Здравствуйте, мыщъх, Вы писали:

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


I>>>- более простой контроль на флоу?

I>>>- исключениефобия?
V>>Я сам не большой фанат исключений. Исключения нужны там, где они нужны. Скажем так, я считаю, в программе должен быть ровно один блок try/catch — в мейн. Все, что бросило исключение — проваливается в самый низ, логгируется и программа завершается.
V>>Если программа может продолжаться — то это не исключение, а возврат ошибки из функции.
V>>Но если объект критически важен, и его несоздание должно вызывать исключение — то надо вызвать исключение, я так считаю.

М>это да. на плюсах нет возможности корректно обработать исключение. скажем, функция foo выполнила кучу операций и в какой-то момент решила открыть файл bar. и тут выяснилось, что файл открыть невозможно. что делать? кидем исключение. ловим его и видим, что (допустим) юзер вытащил флешку или cd/dvd. вот было бы здорово сказать юзеру -- воткни флешку обратно и продолжить выполнние функции foo с того места, в котором было брошено исключение. но увы... это невозможно (если только не реализовать свой диспетчер исключений).


Например можно сделать без всяких диспетчеров так:
enum Stage
{
  Start,
  Step1,
  Step2,
  Step3,
  Finish
};

struct stage_error: std::runtime_error
{
  stage_error(const std::string &message, Stage stage):
    std::runtime_error(message),
    last_stage(stage)
  { }

  Stage last_stage;
}

void foo(..., Stage current = Start)
{
  // на основе значение current выполняем определённые действия и меняем current на значение следующей стадии
  // ...

  // в текущей стадии ошибка!
  throw stage_error("ошибка", current);

  // ...
}

// здесь мы вызываем обработку
{
  try
  {
    foo(...);
  }
  catch (const stage_error &ex)
  {
     // выводим сообщение об ошибке
     // ...(ex.what())

     // просим пользователя одуматься :)

     // вызываем обработку с того самого места
     foo(..., ex.last_stage);
  }
}

Я это написал не для того чтобы поучаствовать в споре "исключения vs коды возврата", а для того чтобы показать что такую задачу можно решить с помощью исключений. Более того, я хочу сказать что в данном конкретном случае механизм обработки ошибок не существенен. В любом случае функция foo должна уметь возобновлять свою работу с определённого места и без венсения изменений в функцию foo решить такую задачу невозможно.
Re[7]: C++ без эксепшенов
От: sts  
Дата: 29.07.11 11:33
Оценка:
ООП на гольном С:
любая функция возвращает код ошибки, а первым параметром принимает this — указатель на структуру.
И получается что-то типа такого:


#define CHECK(x) \
  do {\
    int retcode = (x);\
    if (retcode != OK)\
      return retcode;\
  } while(0)

typedef struct {
    int value;
} my_class;
int my_class_init(my_class* this, int value) {
    this->value = value;
    return OK;
}
int my_class_serialize(my_class* this, char* str, size_t size) {
    if ( snprintf(....
    ...
}

int foo(char* str, size_t size) {
    my_class my_class_inst;
    CHECK(my_class_init(&my_class_inst, 10));
    CHECK(my_class_serialize(&my_class_inst, str, size));
    return OK;
}


только вот RAII нет — нужно по идее собирать списки деинициализации и в CHECK чистить все это дело
в общем, закат солнца вручную.
не знаю кому это сегодня нужно
кроме стрых проектов, написанных так для совместимости с разными страшными компиляторами

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

MZ>On 28.07.2011 22:45, uzhas wrote:


>> а я фанат

>> ненавижу if-ы, они увеличивают цикломатическое число и негавтивно влияют на
>> ковередж (юнит-тестами замучаешься все decisions покрывать)
>> хорошо, когда if находится в классе, а не у каждого клиента этого класса

MZ>Главное даже не if-ы, а корректность программы.


MZ>Вот протокол (сигнатура) метода:


MZ>class Complex

MZ>{
MZ> ...
MZ> Complex divide( const Complex& r ) const;
MZ> ...
MZ>};


MZ>Ну и что ему возвращать при таком вызове:


MZ>Complex res = Complex( 2, 3 ).divide( 0 );


MZ>?


MZ>Если что-то возвращать, программа просто тупо становится

MZ>некорректной. А если вводить "флаги успешности выполнения
MZ>операции" -- сразу становится неуклюжей и неестественной.
Re[2]: Какие исключения кидает STL?
От: igna Россия  
Дата: 29.07.11 13:03
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Без иключений нельзя использовать STL, потому что оно их кидает.


Какие исключения кидает STL?

(Именно STL, а не Standard Library; и именно сама STL, а не пользовательские функции, вызываемые из STL.)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.