C++ without exceptions: back to old days
От: dave_2  
Дата: 28.07.07 11:40
Оценка:
Начался новый проект, платформа ARM где-то 200 Mhz, 16Kb кэша и 32Mb,
компилятор к нему gcc 3.x, при написание маленьких програм выяснилось с что
с возможностями современного C++ придется завязывать, код с поддержкой исключений
генериться каких-то огромных размеров и работает на порядок медленее,
даже если не выбрасывать исключений.

И назрел у меня вопрос а как без исключений-то жили?

Если констуктор делает что-то нетривиальное,
ну например хочется такой класс сделать:

class ConfigReader {
public:
  explicit ConfigReader(const char *fname);
  ~ConfigReader();
  bool get_value(const char *name, int& val);
};



Без исключений придется в каждом методе проверять,
а сконструиравался ли объект, а в живом он состояние вообще.

каторга какая-то а не программирование, как такие вопросы решались?
Re: C++ without exceptions: back to old days
От: Mika Soukhov Stock#
Дата: 28.07.07 11:53
Оценка:
Здравствуйте, dave_2, Вы писали:

_>каторга какая-то а не программирование, как такие вопросы решались?


Решались!? Я два года назад был над одним проектом, так там вообще не было никаких проверок с выбрасыванием исключения. И ничего. Только много в времени в отладчике приходилось проводить.
Re: C++ without exceptions: back to old days
От: pgregory Россия  
Дата: 28.07.07 12:41
Оценка:
Здравствуйте, dave_2, Вы писали:

_>Начался новый проект, платформа ARM где-то 200 Mhz, 16Kb кэша и 32Mb,

_>компилятор к нему gcc 3.x, при написание маленьких програм выяснилось с что
_>с возможностями современного C++ придется завязывать, код с поддержкой исключений
_>генериться каких-то огромных размеров и работает на порядок медленее,
_>даже если не выбрасывать исключений.

А вы не пробовали новый GCC? Или он эту платформу уже не поддерживает?

Традиционные методы жизни без исключений упомянуты у Страуструпа. Он их рассматривает по одному и говорит, чем каждый метод плох :-)
--
In code we trust.
Re[2]: C++ without exceptions: back to old days
От: dave_2  
Дата: 28.07.07 19:36
Оценка:
Здравствуйте, pgregory, Вы писали:

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


_>>Начался новый проект, платформа ARM где-то 200 Mhz, 16Kb кэша и 32Mb,

_>>компилятор к нему gcc 3.x, при написание маленьких програм выяснилось с что
_>>с возможностями современного C++ придется завязывать, код с поддержкой исключений
_>>генериться каких-то огромных размеров и работает на порядок медленее,
_>>даже если не выбрасывать исключений.

P>А вы не пробовали новый GCC? Или он эту платформу уже не поддерживает?


Проблема не в gcc как я понимаю а в стандарте который предложили для ARM ABI,
на каждую функцию в которой может произойти исключения генерится отдельная секция
в исполняемом файле потом это как-то хитро обрабатывается в общем жуть.

P>Традиционные методы жизни без исключений упомянуты у Страуструпа. Он их рассматривает по одному и говорит, чем каждый метод плох
Re[2]: C++ without exceptions: back to old days
От: dave_2  
Дата: 28.07.07 19:38
Оценка:
Здравствуйте, Mika Soukhov, Вы писали:

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


_>>каторга какая-то а не программирование, как такие вопросы решались?


MS>Решались!? Я два года назад был над одним проектом, так там вообще не было никаких проверок с выбрасыванием исключения. И ничего. Только много в времени в отладчике приходилось проводить.


а как проверялся инвариант нахождение объекта в хорошем состоянии?
просто в каждом методе предполагалось что все хорошо, а если
нет то вот тебе отладчик в руки?
Re: C++ without exceptions: back to old days
От: Gaperton http://gaperton.livejournal.com
Дата: 28.07.07 20:16
Оценка: 3 (2) +2
Здравствуйте, dave_2, Вы писали:

_>Начался новый проект, платформа ARM где-то 200 Mhz, 16Kb кэша и 32Mb,

_>компилятор к нему gcc 3.x, при написание маленьких програм выяснилось с что
_>с возможностями современного C++ придется завязывать, код с поддержкой исключений
_>генериться каких-то огромных размеров и работает на порядок медленее,
_>даже если не выбрасывать исключений.

_>И назрел у меня вопрос а как без исключений-то жили?


Ага, допрыгались? Еmbedded разработка — это вам не тут . Нефиг память особо сильно динамически выделять, тогда и эксцепшны особо не нужны.

А жили как? На plain C жили, и до сих пор под embedded на нем пишут. С кодами возворатов, и расширенной информацией, передающейся через глобальные переменные. Посмотри POSIX API — там наглядно показано, как жить без exception.

Да, кстати. Под АРМ должны быть компиляторы поприличнее, чем GCC 3.x. Сам ARM должен давать хорошие оптимизирующие компиляторы. Имеет смысл купить средства разработки под ARM. Глядишь, и exceptions будут нормально работать.
Re: C++ without exceptions: back to old days
От: Cyberax Марс  
Дата: 28.07.07 20:23
Оценка:
dave_2 wrote:
> Начался новый проект, платформа ARM где-то 200 Mhz, 16Kb кэша и 32Mb,
> компилятор к нему gcc 3.x, при написание маленьких програм выяснилось с что
> с возможностями современного C++ придется завязывать, код с поддержкой
> исключений
> генериться каких-то огромных размеров и работает на порядок медленее,
> даже если не выбрасывать исключений.
А не пробовал менять тип ABI и тип исключений в GCC (его для этого надо
пересобрать — рекомендую использовать buildroot)? Да, и естественно
после сборки надо делать strip.

У меня MIPS 4Kc V0.11 c 175Mhz и 32Mb памяти, uClibc+Busybox.
Exception'ы живут вполне нормально, даже части Буста использую.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[2]: C++ without exceptions: back to old days
От: Gaperton http://gaperton.livejournal.com
Дата: 28.07.07 20:56
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>У меня MIPS 4Kc V0.11 c 175Mhz и 32Mb памяти, uClibc+Busybox.

C>Exception'ы живут вполне нормально, даже части Буста использую.

Как интересно. Это что же у тебя за девайс? Раутер какой-нить, или свитч?
Re[3]: C++ without exceptions: back to old days
От: Cyberax Марс  
Дата: 28.07.07 22:27
Оценка:
Gaperton wrote:
> C>У меня MIPS 4Kc V0.11 c 175Mhz и 32Mb памяти, uClibc+Busybox.
> C>Exception'ы живут вполне нормально, даже части Буста использую.
> Как интересно. Это что же у тебя за девайс? Раутер какой-нить, или свитч?
http://www.routerboard.com/rb100.html — используем RouterBoard150.

Используем его в качестве "шлюза" для устройств со "странным" (не
IP-based) протоколом, поэтому 5 отдельных физических интерфейсов очень
помогают. Шлюз еще используется как достаточно интеллектуальное
буферизирующее устройство, так что для этого и взяли достаточно мощную
встроеную систему.

Ну и с 32Mb RAM и 64Mb NAND можно себя особо не ограничивать
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re: C++ without exceptions: back to old days
От: minorlogic Украина  
Дата: 29.07.07 05:32
Оценка:
Знаю 2 распространенных способа.

1. Передавать код ошибки через все возможные ветки где может быть ошибка типа ERROR_VALUE.
Недостатки:
размер кода растет в разы и логика работы прячется за грудой кода по трансляции ошибок.
конечно програмисты стремяться писать так чтобы уменьшить число ф-ций с возможными ошибками , зачастую просто маскируя проблемы.

2. Некий глобальный объект который может запоминать последнюю ошибку или историю ошибок. SetLastError GetLastError.

про RAII конечно можно забыть, все ручками.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: C++ without exceptions: back to old days
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 29.07.07 09:41
Оценка:
Здравствуйте, dave_2

_>Без исключений придется в каждом методе проверять,

_>а сконструиравался ли объект, а в живом он состояние вообще.

_>каторга какая-то а не программирование, как такие вопросы решались?


Я бы выбирал один из следующих вариантов:

1. Установка глобальной переменной errno в каждой подпрограмме, которая может приводить к каким-либо ошибкам (т.е., по сути, в каждой подпрограмме). Программирование тогда выглядело бы как-то так:

ConfigReader config( "/etc/myconfig" );
if( 0 == errno )
  // Все нормально.
  ...


Главных минусов здесь два:

Во-первых, в каждой подпрограмме нужно устанавливать errno в ноль, чтобы сбросить возможное наследие предыдущих вызовов. Соответственно, это легко забыть делать. Помогают, например, макросы, вроде FUNCTION_PROLOG:
ConfigReader::ConfigReader( const char * fileName )
  {
    // Здесь обнуляется errno и, возможно, делается еще что-то.
    FUNCTION_PROLOG( "ConfigReader::ConfigReader" );
    ...
  }

Если на целевой платформе недостаточно продвинутые средства для трасировки и профилирования программ, то в FUNCTION_PROLOG можно запрятать какие-нибудь доморощенные средства трассировки и/или профилирования.

Во-вторых, для установки кода ошибок и проверки успешности операции нужно выполнять больше действий -- установка/контроль errno выполняется в отдельных строках кода:
ConfigReader::ConfigReader( const char * fileName )
  {
    FILE * f = fopen( fileName, "r" );
    if( !f )
      {
        // Здесь ошибку диагностировали, но нужно установить
        // собственный код ошибки перед возвратом.
        errno = ...;
        return;
      }
    ...
  }
...
ConfigReader config( "/etc/myconfig" );
// Требуется отдельная строка для проверки успешности операции.
if( 0 == errno )
  ...


2. Возврат кода ошибки в каждой подпрограмме, которая может приводить к каким-либо ошибкам (т.е., по сути, в каждой подпрограмме). В этом случае нужно отказаться от выполнения каких-либо серьезных действий в конструкторах объектов и перенести их в специальные методы иницииализации или фабрики объектов. Например, с процедурой инициализации:
ConfigReader::ConfigReader( const char * fileName )
  {
  // Только сохраняет имя файла, но ничего не делает.
  }

int ConfigReader::load()
  {
    FILE * f = fopen( fileName, "r" );
    if( !f )
      return <код ошибки>;
    ...
    return 0; // Все OK.
  }
...
int error = 0;
ConfigReader config( "/etc/myconfig" );
if( 0 != ( error = config.load() ) )
  ... // Ошибок нет.

Или с фабрикой:
int makeConfigReader( const char * fileName, auto_ptr< ConfigReader > & readerReceiver )
  {
    FILE * f == fopen( fileName, "r" );
    if( !f )
      return <код ошибки>;
    ...
    readerReceiver = auto_ptr< ConfigReader >( new ConfigReader( ... ) );
    return 0;
  }
...
int error = 0;
auto_ptr< ConfigReader > reader;
if( 0 == ( error = config.load() ) )
  ... // Ошибок нет.


Небольшим недостатком данного подхода можно считать то, что практически всегда приходится заводить переменную error, в которую помещать код возврата вызванного метода. Из-за чего вызовы методов оказываются более громоздкими.

Для устранения этого недостатка можно использовать следующий подход, который является базовым механизмом индикации ошибок в библиотеке ACE и во многих функциях WinAPI, возвращающих BOOL.

3. Код ошибки сохраняется в errno, а возвращаемое значение метода сообщает только была ли какая-нибудь ошибка или нет. Например, метод возвращает 0, если все нормально, и -1 в случае ошибки:
int makeConfigReader( const char * fileName, auto_ptr< ConfigReader > & readerReceiver )
  {
    FILE * f = fopen( fileName, "r" );
    if( !f )
      {
        errno = <код ошибки>;
        return -1;
      }
    ...
  }

auto_ptr< ConfigReader > reader;
if( 0 == config.load() )
  ... // Ошибок нет.


По моему, такой подход усложняет написание библиотечных функций (т.к. требует сброса/установки errno), но упрощает использование библиотечных функций. Хотя за счет специальных макросов FUNCTION_PROLOG и ERROR_RETURN трудоемкость написания библиотек можно существенно снизить. Но сам я предпочитаю подход N2.


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

1. Заведение в классе специального флага, который указывает, что инвариант класса был нарушен. Например, если конструктор не отработал до конца и пользоваться экземпляром нельзя. Этот флаг затем должен проверяться во всех public-методах класса:
ConfigReader::ConfigReader( const char * fileName )
  : m_isOk( false )
  {
    ...
    // Только в конце конструктора можно установить isOk в true.
    m_isOk = true;
  }
int ConfigReader::intKey( const char * keyName, int & valueReceiver )
  {
    if( !isOk() )
      return <код ошибки>;
    ...
  }

Можно завести public-метод bool isOk() const, который можно использовать для проверки того, что экземпляр находится в корректном состоянии:
ConfigReader config( "/etc/myconfig" );
if( config.isOk() )
  ...

но лучше не полагаться на то, что пользователи класса ConfigReader прилежно использовать метод isOk().

2. Отказ от сложных конструкторов в которых выполняются какие-нибудь действия, способные нарушить инварианты класса. Т.е. вынести инициализацию объекта в специальные методы-фабрики, которые сначала выполняют все действия, а затем, если все нормально, конструируют объект.

Хотя, на практике, лучше использовать комбинированную технику: простые конструкторы и методы инициализаторы/фабрики, а так же признак isOk, который контролируется в public-методах класса. Такой подход позволяет обрабатывать нарушения инвариантов во время жизни экземпляра. Например, если есть класс, обслуживающий сетевое соединение, то после диагностирования разрыва соединения можно сбросить m_isOk и все последующие обращения к методам этого экземпляра будут сразу выдавать код ошибки "соединение потеряно".


Ну и в качестве лирического отступления...
Не так уж и сложно писать без исключений. Временами даже в чем-то проще. Нужно привыкнуть к коду "лесенкой":
int doSomething()
  {
    int error = 0;
    if( 0 == ( error = prepare() ) )
      if( 0 == ( error = doMainAction() ) )
        if( 0 == ( error = checkResults() ) )
          error = cleanupResources();
    return error;
  }

А так же использовать классы с очисткой ресурсов в деструкторах для освобождения ресурсов вместо того, чтобы обрабатывать ветви else или писать специальные clean-секции. Т.е. делать что-то типа:
int sendPackageToHost( const Package & pkg, const HostInfo & host )
  {
    int error = 0;
    auto_ptr< BinaryBuffer > buffer;
    if( 0 == ( error = createBuffer( pkg.binaryDataSize(), buffer ) ) )
      {
        if( 0 == ( error = packPackageToBuffer( pkg, *buffer ) ) )
          {
            auto_ptr< HostConnection > connection;
            if( 0 == ( error = createConnectionToHost( host, connection ) ) )
              error = sendToConnection( *connection, *buffer );
          }
      }
    return error;
  }

вместо чистого C-шного подхода:
int sendPackageToHost( const Package & pkg, const HostInfo & host )
  {
    int error = 0;
    BinaryBuffer * buffer = 0;
    HostConnection * connection = 0;
    
    if( 0 == ( error = createBuffer( pkg.binaryDataSize(), buffer ) ) )
      if( 0 == ( error = packPackageToBuffer( pkg, *buffer ) ) )
        if( 0 == ( error = createConnectionToHost( host, connection ) ) )
          error = sendToConnection( *connection, *buffer );

    if( connection )
      delete connection;
    if( buffer )
      delete buffer;

    return error;
  }


По моему опыту, писать без исключений и писать только с исключениями не так уж и сложно. Гораздо сложнее писать на смеси стилей -- когда часть библиотек использует только исключения, а другая часть вообще не использует исключений.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: C++ without exceptions: back to old days
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.07.07 10:32
Оценка: 27 (3) +1
Здравствуйте, eao197, Вы писали:

E>Я бы выбирал один из следующих вариантов:


Для полноты картины надо привести один вариант: использование setjmp/longjmp для _эмуляции_ механизма исключений. (На самом деле, многие ранние варианты реализации исключений использовали его же). Выглядит это следующим образом:

1. Заводится один глобальный (для однонитевой программы) и для каждой нити (можно через TLS, можно через declspec(thread)) jmp_buf текущего обработчика.

2. Все try-catch, а также все неявные try-finally, возникающие в блоках с нетривиальными деструкторами и в конструкторах с ними же, заменяются на установку своего перехватчика в буфер:

    extern jmp_buf global_jump;
    jmp_buf saved_jump = global_jump;
    int jmp_ret = setjmp(global_jump);
    if (jmp_ret == 0) {
        // здесь пишется try-блок
    } else {
        // нам прислали исключение, обрабатываем
        if (передать его дальше) {
            global_jump = saved_jump;
            longjmp(global_jump, jmp_ret);
        }
    }
    global_jump = saved_jump; // восстановить в любом случае


Обработка исключения делается в зависимости от сути блока:
— в неявном try-finally вызываются нетривиальные деструкторы, затем восстанавливается старое состояние global_jump и делается longjmp() по нему;
— если в try-catch исключение не поймано — то же самое;
— независимо от того, поймано исключение в try-catch или нет — надо восстановить старое состояние global_jump (запомненное в saved_jump) по любому выходу из блока.

Для держания информации о текущем исключении заводятся соответствующие глобальные (тредовые) переменные.

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

E>1. Установка глобальной переменной errno в каждой подпрограмме, которая может приводить к каким-либо ошибкам (т.е., по сути, в каждой подпрограмме). Программирование тогда выглядело бы как-то так:


E>
E>ConfigReader config( "/etc/myconfig" );
E>if( 0 == errno )
E>  // Все нормально.
E>  ...
E>


E>Главных минусов здесь два:


E>Во-первых, в каждой подпрограмме нужно устанавливать errno в ноль, чтобы сбросить возможное наследие предыдущих вызовов. Соответственно, это легко забыть делать. Помогают, например, макросы, вроде FUNCTION_PROLOG:


Есть ещё одна существенная проблема: по Posix функция обязана ставить адекватный errno в случае сигнализации об ошибке, но никому не обязана сохранять предыдущее значение в случае нормального возврата (и часто оно меняется — в результате каких-то промежуточных ошибочных попыток). Поэтому если это используется, то вокруг функции надо ещё сделать враппер, который чистит errno в случае нормального возврата. Как по мне, это слишком сложно (и возможно не везде; например, это хорошо получается с gcc'шным расширением ({...}), но крайне неудобно без него).

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


Такой перенос сам по себе нужен во многих случаях.

E>2. Отказ от сложных конструкторов в которых выполняются какие-нибудь действия, способные нарушить инварианты класса. Т.е. вынести инициализацию объекта в специальные методы-фабрики, которые сначала выполняют все действия, а затем, если все нормально, конструируют объект.


Да, это практичнее (в отличие от всяких isOk() в конструкторе)

E>Ну и в качестве лирического отступления...

E>Не так уж и сложно писать без исключений. Временами даже в чем-то проще. Нужно привыкнуть к коду "лесенкой":
E>
E>int doSomething()
E>  {
E>    int error = 0;
E>    if( 0 == ( error = prepare() ) )
E>      if( 0 == ( error = doMainAction() ) )
E>        if( 0 == ( error = checkResults() ) )
E>          error = cleanupResources();
E>    return error;
E>  }
E>


Лучше уж или "goto cleanup", или псевдо-цикл (do {} while(0)) с выходом break'ом.

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


угу.
The God is real, unless declared integer.
Re[3]: C++ without exceptions: back to old days
От: Константин Л. Франция  
Дата: 29.07.07 16:35
Оценка:
Здравствуйте, netch80, Вы писали:

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


E>>Я бы выбирал один из следующих вариантов:


N>Для полноты картины надо привести один вариант: использование setjmp/longjmp для _эмуляции_ механизма исключений. (На самом деле, многие ранние варианты реализации исключений использовали его же). Выглядит это следующим образом:


Насколько я понял из своего опыта, в Acrobar Reader на них построен механизм исключений.

[]
Re: C++ without exceptions: back to old days
От: NikeByNike Россия  
Дата: 29.07.07 16:47
Оценка:
Здравствуйте, dave_2, Вы писали:

_>Без исключений придется в каждом методе проверять,

_>а сконструиравался ли объект, а в живом он состояние вообще.

_>каторга какая-то а не программирование, как такие вопросы решались?


Посмотри как в симбе решается Подобный подход уже апробирован и достаточно спокойно делается руками.
Начать от сюда: http://www.rsdn.ru/article/pda/symbian.xml
Автор(ы): Дмитрий Москальчук
Дата: 06.11.2005
В статье затронуты вопросы основных отличий процесса программирования под Symbian от программирования под такие операционные системы, как MS Windows или Linux.
Требуется знание С++
Нужно разобрать угил.
Re[2]: C++ without exceptions: back to old days
От: Cyberax Марс  
Дата: 29.07.07 17:00
Оценка: +1
Здравствуйте, NikeByNike, Вы писали:

NBN>Посмотри как в симбе решается Подобный подход уже апробирован и достаточно спокойно делается руками.

NBN>Начать от сюда: http://www.rsdn.ru/article/pda/symbian.xml
Автор(ы): Дмитрий Москальчук
Дата: 06.11.2005
В статье затронуты вопросы основных отличий процесса программирования под Symbian от программирования под такие операционные системы, как MS Windows или Linux.
Требуется знание С++

За этот подход в Симбе дизайнера надо придушить. ЧТО УГОДНО будет лучше этих %&*%#$$# LEAVE'ов, даже явная проверка кодов возврата.

ИМХО, без исключений самой нормальной формой будет использование "goto error_exit" для очистки состояния + код возврата. Возможна еще thread-local переменная для расширеного сообщения об ошибке.
Sapienti sat!
Re[3]: C++ without exceptions: back to old days
От: NikeByNike Россия  
Дата: 29.07.07 17:19
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>За этот подход в Симбе дизайнера надо придушить. ЧТО УГОДНО будет лучше этих %&*%#$$# LEAVE'ов, даже явная проверка кодов возврата.


C>ИМХО, без исключений самой нормальной формой будет использование "goto error_exit" для очистки состояния + код возврата. Возможна еще thread-local переменная для расширеного сообщения об ошибке.


Да ну, хоть такая система, а всёравно лучше чем "иди на". Писанины и геммороя меньше.
Нужно разобрать угил.
Re[4]: C++ without exceptions: back to old days
От: Cyberax Марс  
Дата: 29.07.07 21:13
Оценка:
Здравствуйте, NikeByNike, Вы писали:

C>>За этот подход в Симбе дизайнера надо придушить. ЧТО УГОДНО будет лучше этих %&*%#$$# LEAVE'ов, даже явная проверка кодов возврата.

C>>ИМХО, без исключений самой нормальной формой будет использование "goto error_exit" для очистки состояния + код возврата. Возможна еще thread-local переменная для расширеного сообщения об ошибке.
NBN>Да ну, хоть такая система, а всёравно лучше чем "иди на". Писанины и геммороя меньше.
Не меньше. Зато гемора намного больше — нужно писать в exception-safe-стиле без нормальных автоматических деструкторов.

Да, все стандартные библиотеки типа STL и вообще почти все остальное — ты тоже использовать не можешь.
Sapienti sat!
Re[5]: C++ without exceptions: back to old days
От: NikeByNike Россия  
Дата: 30.07.07 05:11
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>>>ИМХО, без исключений самой нормальной формой будет использование "goto error_exit" для очистки состояния + код возврата. Возможна еще thread-local переменная для расширеного сообщения об ошибке.

NBN>>Да ну, хоть такая система, а всёравно лучше чем "иди на". Писанины и геммороя меньше.
C>Не меньше. Зато гемора намного больше — нужно писать в exception-safe-стиле без нормальных автоматических деструкторов.

C>Да, все стандартные библиотеки типа STL и вообще почти все остальное — ты тоже использовать не можешь.


Возможно у нас разный первый опыт работы с симбой
Мне кажется, что работа даже с такой недоделанной системой (особенно при использовании 2-3 хелперов) — всёравно лучше, чем проверка возращаемых значения и производные мутации.

STL я портировал и так же нормально использовал. Восновном алгоритмы и основные контейнеры — map, set, vector, string (list свой, односвязный).
Их основное исключение о нехватке памяти — нужно ловить только на этапе отладки. В релизе в этом нет необходимости (покрайней мере в наших проектах), из-за того что они работают с уже известным количеством памяти и мы просто в начале проверяем что её хватает. Если с памятью таки случится беда — прогу правильно уронит собственный менеджер памяти. Он освободит важные ресурсы, без вызова деструкторов освободит всю память, выведет сообщение и закроет программу.

Плюс к такой системе — немножко большая скорость работы, по сравнению с проверкой возвращаемого значения или настоящими исключениями.

P.S.
Мы так же позаимствовали из буста систему сериализации...

P.S.S.
Сам по себе буст — довольно не оптимален, что критично для слабой платформы. Поэтому умные поинтеры и функторы — так же самописные.

P.S.S.S.
На симбе — занимался играми, обработкой звука и довольно наворочанным мессенжером.
Нужно разобрать угил.
Re: C++ without exceptions: back to old days
От: no4  
Дата: 30.07.07 05:25
Оценка: 12 (1)
Здравствуйте, dave_2, Вы писали:

_>И назрел у меня вопрос а как без исключений-то жили?


Я не знаю, поможет ли тебе это, но вдруг натолкнет на какие-нибудь свои идеи.

Я это делал на BAAN.

Пишутся функции int getError(); void setError(int _code) которые просто устанавливают некую глобальную переменную

Пишется набор макросов
// стандартная обработка для void функций
#define HANDLE.VOID if (getError()!=ERR_OK) return;
// стандартная обработка для int функций
#define HANDLE.NUM if (getError()!=ERR_OK) return 0;

// просто сокращение
#define HN HANDLE.NUM
#define HV HANDLE.VOID


Использование

int myFunction(){
  someOtherFunction() HI
    someOtherFunctio2() HI
}
void myVoidFunction()
{
    myFunction() HV
    myFunction2() HV
}


собственно, в макросы можно добавить еще запихивание данных о стеке вызовов и т.д.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: C++ without exceptions: back to old days
От: Вертер  
Дата: 30.07.07 19:53
Оценка:
_>И назрел у меня вопрос а как без исключений-то жили?

у нас было правило: никаких new и delete
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.