Симуляция блока try-finally для С++
От: Проскурня М.О. Россия  
Дата: 23.03.04 03:50
Оценка: 7 (3) -16
Статья:
Симуляция блока try-finally для С++
Автор(ы): Проскурня М.О.
Дата: 19.03.2004
В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.


Авторы:
Проскурня М.О.

Аннотация:
В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.
Re: Симуляция блока try-finally для С++
От: Шахтер Интернет  
Дата: 23.03.04 04:29
Оценка: 2 (2) +9
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>Статья:

ПМО>Симуляция блока try-finally для С++

ПМО>Авторы:

ПМО> Проскурня М.О.

ПМО>Аннотация:

ПМО>В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.

И она там нафиг не нужна, поскольку есть деструкторы. Мне вот интересно, почему писать в каждом месте где нужно, скажем, закрыть файл, код для закрытия файла это не напряжно, а написать один раз деструктор -- это страшно тяжело.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Симуляция блока try-finally для С++
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 23.03.04 05:33
Оценка:
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.


О Великий и Могучий яз..., то есть препроцессор
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Симуляция блока try-finally для С++
От: Par-zzz  
Дата: 23.03.04 05:34
Оценка:
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>Статья:



ПМО>Авторы:

ПМО> Проскурня М.О.

ПМО>Аннотация:

ПМО>В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.

Конструкции try-finally ИМХО встречаются гораздо реже нежели try-catch-finaly. И такие экзотические catch, что делегируют исключение внешнему обработчику достаточно редкие явления, я бы заюзал деструктор, если мне надо освободить ресурсы, а исключения бы просто не ловил.
/**
* у человека столько проблем, сколько он их себе создает
*/
Re: Симуляция блока try-finally для С++
От: e-Xecutor Россия  
Дата: 23.03.04 05:57
Оценка:
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>Статья:



ПМО>Авторы:

ПМО> Проскурня М.О.

ПМО>Аннотация:

ПМО>В некоторых языках программирования существует конструкция вида try-finally, в которой секция finally выполнялась обязательно, как при возникновении исключений, так и при нормальном ходе выполнения программы. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора.

Далеко не все препроцессоры прожуют такую конструкцию.
Про деструкторы и т.д. уже сказали
Re: Симуляция блока try-finally для С++
От: dv Россия derevyanko.blogspot.com
Дата: 23.03.04 06:05
Оценка: 1 (1)
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>Аннотация:

ПМО>В некоторых языках программирования существует конструкция вида try-finally.. Поскольку в языке C++ такой конструкции явно не присутствует, мы можем попытаться описать её самостоятельно, прибегая к помощи макропрепроцессора

У Andrei Alexandrescu есть статья "Change the Way You Write Exception-Safe Code — Forever", в которой приведено элегантное и удобное на практике решение, позволяющее эмулировать finally с помощью шаблонного класса ScopeGuard.
Киса, скажите как художник — художнику: вы рисовать умеете?
Re: Симуляция блока try-finally для С++
От: folk Россия  
Дата: 23.03.04 06:19
Оценка:
Здравствуйте, Проскурня М.О., Вы писали:

Ну и мои 3 коп.
Во-1х запятая в таком finally-блоке недопустипа, поскольку будет считаться разделителем аргументов макроса.
Во-2х finally предполагает что переменные определяются отдельно до их использования — перед началом try-блока, что является плохим стилем в C++.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re: Симуляция блока try-finally для С++
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.03.04 08:31
Оценка: 25 (2)
Здравствуйте, Проскурня М.О., Вы писали:

Если немного присмотреться, то видно, что в статье пример не совсем в тему. Используется ручное управление памятью.

В данном примере достаточно механизмов SEH(для вындоуза). Вот как это будет выглядеть.

char* buffer = NULL;
int   fd = -1, numread;
__try
{
   buffer = new char [256];
   fd = open ( "data", "r" );  // открываем файл и читаем по 256 символов
   while ( 0 < ( numread = read ( fd, buffer, 256 ) ) )
   {
       critical ( buffer, numread );  // вызов критической функции
   }
}
__finally 
{
   if ( 0 < fd ) close ( fd );  // он является текстовым параметром макроса
   if ( buffer ) delete buffer; 
}


С макросом из статьи много проблем.
1. Не факт что все выражения подымутся пропроцессором.
2. Количество кода обработки удваивается. Не много, но часто это неприятно.
3. В макросе есть throw. Этого не следует делать. Программист должен сам расставлять throw.
4. В ряде случаев catch(...) никуда не должен передавать исключение.

На С++ проще использовать коллекции на стеке, нежели динамически управлять памятью. Эффект тот же.
Роль finally сыграет деструктор, который вызовется в любом случае при локальной или глобальной раскрутке.
Посему макрос в статье нужен лишь для того, что бы привлечь читателя к проблеме использования механизма исключений.
Re: Симуляция блока try-finally для С++
От: Аноним  
Дата: 23.03.04 09:12
Оценка:
Здравствуйте, Проскурня М.О., Вы писали:

ПМО>Статья:


1) Отличный от привычного синтаксис.
2) Когда я использую "нормальный" finally — языковая среда гарантирует, что код, заключенный в него будет вызван (почти) всегда.

try {
char* sz = (0, new char[128]);
// use it here
}
catch(const bad_alloc&) {
// memory exhausted, process it
throw;
}
finally (
// может ли случиться так, что не попадем сюда? да.
)
Re[2]: Симуляция блока try-finally для С++
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.03.04 09:15
Оценка: 5 (5)
Здравствуйте, Plutonia Experiment, Вы писали:

PE>С макросом из статьи много проблем.

PE>1. Не факт что все выражения подымутся пропроцессором.
PE>2. Количество кода обработки удваивается. Не много, но часто это неприятно.
PE>3. В макросе есть throw. Этого не следует делать. Программист должен сам расставлять throw.
PE>4. В ряде случаев catch(...) никуда не должен передавать исключение.


Еще момент, самый основной, который я упустил.

finally должен срабавтывать и в случае return в блоке try. В случае с макросом это не так.
Re[2]: Симуляция блока try-finally для С++
От: Atomic Max Россия  
Дата: 23.03.04 14:52
Оценка:
2 Аноним:


А> 2) Когда я использую "нормальный" finally — языковая среда гарантирует, что код, заключенный в него будет вызван (почти) всегда.


А>try {

А> char* sz = (0, new char[128]);
А> // use it here
А>}
А>catch(const bad_alloc&) {
А> // memory exhausted, process it
А> throw;
А>}
А>finally (
А> // может ли случиться так, что не попадем сюда? да.
А>)

Я привёл пример симуляции конструкции try-finally, а не try-catch-finally. Ваш код должен содержать два вложенных блока try { try {} catch {} } finally (), иначе ерунда получается.
Re[2]: Симуляция блока try-finally для С++
От: Atomic Max Россия  
Дата: 23.03.04 14:56
Оценка:
2 Шахтер:

Ш>И она там нафиг не нужна (симуляция try-finally), поскольку есть деструкторы. Мне вот интересно, почему писать в каждом месте где нужно, скажем, закрыть файл, код для закрытия файла это не напряжно, а написать один раз деструктор -- это страшно тяжело.


Отвечаю:
Иногда методы используют не обёрнутые в классы ресурсы. Если есть возможность обернуть, то я с вами согласен.
Re[3]: Симуляция блока try-finally для С++
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.03.04 15:03
Оценка:
Здравствуйте, Atomic Max, Вы писали:

AM>Я привёл пример симуляции конструкции try-finally, а не try-catch-finally. Ваш код должен содержать два вложенных блока try { try {} catch {} } finally (), иначе ерунда получается.


Ты перечитай его сообщение. Макрос дает всего лишь catch(...).

А try-finally даже наполовину не получилась. Не все отслеживается. Толку от такого finally ?
Re[3]: Симуляция блока try-finally для С++
От: Plutonia Experiment Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.03.04 15:05
Оценка:
Здравствуйте, Atomic Max, Вы писали:

AM>Отвечаю:

AM>Иногда методы используют не обёрнутые в классы ресурсы.

В этом случае рулит SEH
Re[3]: Симуляция блока try-finally для С++
От: Шахтер Интернет  
Дата: 24.03.04 00:18
Оценка:
Здравствуйте, Atomic Max, Вы писали:

AM>2 Шахтер:


Ш>>И она там нафиг не нужна (симуляция try-finally), поскольку есть деструкторы. Мне вот интересно, почему писать в каждом месте где нужно, скажем, закрыть файл, код для закрытия файла это не напряжно, а написать один раз деструктор -- это страшно тяжело.


AM>Отвечаю:

AM>Иногда методы используют не обёрнутые в классы ресурсы. Если есть возможность обернуть, то я с вами согласен.

/* main.cpp */ 

#include <iostream>

using namespace std;

int AllocResource() 
 {
  cout << "AllocResource()" << endl ;
  return 666;
 }

void FreeResource(int n) 
 {
  cout << "FreeResource(" << n << ")" << endl ;
 }

/* main() */ 

int main()
 {
  int n=AllocResource();
  
  struct DeleteClass_n { int todel; DeleteClass_n(int todel_) : todel(todel_) {} ~DeleteClass_n() { FreeResource(todel); } } deleteObject_n(n);
 
  return 0;
 }


И никаких try finally.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Симуляция блока try-finally для С++
От: Аноним  
Дата: 25.03.04 12:21
Оценка: +1
Здравствуйте, Atomic Max, Вы писали:

AM>Иногда методы используют не обёрнутые в классы ресурсы. Если есть возможность обернуть, то я с вами согласен.


1)Вы не могли бы привести пример ресурсов которые _нельзя_ безопасно обернуть используя идиому деструктора?

2)Фокус с finally на основе catch(...) будет работать не во всех компиляторах. В частости попробуйте в gcc такой код


try
{
  int* pInt = 0;
  *pInt = 1;
}
catch(...)
{
  std::cout<<"Yes! I have caught it!\n";
}


блок внутри catch(...) гарантированно не выполниться. В общем случае catch(...) перехватывает все необработанные раннее иключения. Т.е. те которые генерируются throw. То что структурные исключения в VC++ перехватываются в catch(...) — просто бонус microsoft, а не свойство языка. Конструкция try-finally есть в Java, но там нет деструторов (таких, к как в с++). А в с++ эта конструкция просто не нужна. К тому же она строиться целиком на макросах
Re[3]: Симуляция блока try-finally для С++
От: Alexey_ch Швейцария  
Дата: 26.03.04 15:58
Оценка:
Здравствуйте, Atomic Max, Вы писали:

AM>2 Шахтер:


Ш>>И она там нафиг не нужна (симуляция try-finally), поскольку есть деструкторы. Мне вот интересно, почему писать в каждом месте где нужно, скажем, закрыть файл, код для закрытия файла это не напряжно, а написать один раз деструктор -- это страшно тяжело.


AM>Отвечаю:

AM>Иногда методы используют не обёрнутые в классы ресурсы. Если есть возможность обернуть, то я с вами согласен.

Если в этом коде ловить исключения, то будет полный аналог try...catch...finally.

//______________________________________________________________________________Function
//
//    int CSoundConverter::ConvertMediaFileToMp3(HMMIO hInputFile, HMMIO hOutputFile, 
//                                WAVEFORMATEX* pSrcFormat, WAVEFORMATEX* pDstFormat)
//
//        This function converts WAV file to MP3 using 
//        acmXXX functions. It gets source format from the input file.
//

int CSoundConverter::ConvertMediaFileToMp3(HMMIO hInputFile, HMMIO hOutputFile, 
                            WAVEFORMATEX* pSrcFormat, WAVEFORMATEX* pDstFormat)
{
    //__________________________
    //
    //    class vars
    //
    //        Local class to simplify cleanup on function exit
    //
    class vars
        {
        public:
            HACMSTREAM stream;

            BYTE pInputBuf [CONVERSION_BUFFER_MAX_LEN]; // conversion buffer
            BYTE* pOutputBuf;

            DWORD dwInputBufferLen;            // input buffer lenght that will
                                            // be used in conversion

            DWORD dwOutputBufferLen;        // output buffer lenght that will
                                            // be used in conversion

            vars()
                {
                CSoundFormatDetails::hacmDriver    = NULL;
                stream                            = NULL; 
                pOutputBuf                        = NULL;
                }

            ~vars()
                {
                if (pOutputBuf)
                    delete [] pOutputBuf;

                if (stream)
                    {
                    //
                    //    Close conversion stream
                    //
                    acmStreamClose(stream, 0);
                    }

                if (CSoundFormatDetails::hacmDriver)
                    {
                    //
                    //    Close driver handle
                    //
                    acmDriverClose(CSoundFormatDetails::hacmDriver, 0);
                    }
                }
        } local;

    //
    //    Open ACM driver for conversion
    //        
    MMRESULT res;
    res = acmDriverOpen (    &CSoundFormatDetails::hacmDriver,
                            CSoundFormatDetails::hacmDriverID, 
                            0
                        );
    if (res) 
        return CONV_CODEC_UNAVAILABLE;

    //
    //    Open conversion stream
    //
    res = acmStreamOpen(&local.stream, CSoundFormatDetails::hacmDriver,
        pSrcFormat, pDstFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME);

    if (res)
    {
        OutputDebugString("acmStreamOpen() has failed!\n");
        return CONV_UNABLE_PRODUCE_DST_FORMAT;
    }

    //
    //    Calculate input buffer size (counting input blocks granuality)
    //
    local.dwInputBufferLen = 
        ((unsigned long)(CONVERSION_BUFFER_MAX_LEN / pSrcFormat->nBlockAlign)) * (pSrcFormat->nBlockAlign);

    //
    //    See what buffers sizes are required for conversion
    //
    res = acmStreamSize(local.stream, local.dwInputBufferLen, &local.dwOutputBufferLen, ACM_STREAMSIZEF_SOURCE);
    if (res)
    {
        OutputDebugString("acmStreamSize() has failed!\n");
        return CONV_UNABLE_PRODUCE_DST_FORMAT;
    }
    else
        {
        //
        //    Allocate memory for output buffer
        //
        local.pOutputBuf = new BYTE [local.dwOutputBufferLen];
        if (!local.pOutputBuf)
            return CONV_NO_MEMORY;
        }

.....
Re: Симуляция блока try-finally для С++
От: iliks Россия http://iliks.livejournal.com
Дата: 07.09.05 17:16
Оценка:
ПМО>В некоторых языках программирования существует конструкция вида try-finally...

А в С++ НЕ существует! И не потому, что авторы не доглядели — Страуструп пишет, что это было полностью осознанное решение. Нужда в finally пропадает абсолютно при использовании техники RAII (выделение ресурса есть инициализация). finally в Java по сути только усложняет внешний вид кода. При RAII нам вообще локально нет нужды писать никакие try и поэтому код

try
{
}
catch
{
}
finally
{
}

превращается в элегентное

{
Resource r();
//use r...
}

всё!
Re[2]: Симуляция блока try-finally для С++
От: Glоbus Украина  
Дата: 08.09.05 07:14
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>И она там нафиг не нужна, поскольку есть деструкторы. Мне вот интересно, почему писать в каждом месте где нужно, скажем, закрыть файл, код для закрытия файла это не напряжно, а написать один раз деструктор -- это страшно тяжело.


Полностью поддерживаю. Да и вообще — лепят горбатого к стенке — то проперти, то try/finally,...
Удачи тебе, браток!
Re[4]: Симуляция блока try-finally для С++
От: Awaken Украина  
Дата: 08.09.05 08:15
Оценка:
Здравствуйте, Plutonia Experiment, Вы писали:

PE>Здравствуйте, Atomic Max, Вы писали:


AM>>Отвечаю:

AM>>Иногда методы используют не обёрнутые в классы ресурсы.

PE>В этом случае рулит SEH


SEH рулит в коде на C но не C++ т.к. блок обработки SEH ничего не знает про деструкторы C++
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.