Освобождение ресурсов & обработка ошибок
От: Аноним  
Дата: 04.08.06 03:28
Оценка:
Вот такая ситуация
HANDLE h1 = Somefunc1();
if (h1 == NULL)  return ERROR_CODE;

HANDLE h2 = Somefunc2();
if (h2 == NULL)  {
   CloseHandle(h2);
   return ERROR_CODE;
}

HANDLE h3 = Somefunc3();

if (h3 == NULL)  {
   CloseHandle(h1);
   CloseHandle(h2);
   return ERROR_CODE;
}

HANDLE h4 = Somefunc4();

if (h3 == NULL)  {
   CloseHandle(h1);
   CloseHandle(h2);
   CloseHandle(h3);
   return ERROR_CODE;
}

if (Condition1)  {
      DoSomething();
      CloseHandle(h1);
      CloseHandle(h2);
      CloseHandle(h3);
      return OK_1;
}

if (Condition2)  {
      DoSomething();
      CloseHandle(h1);
      CloseHandle(h2);
      CloseHandle(h3);
      return OK_2;
}
//...
CloseHandle(h1);
CloseHandle(h2);
CloseHandle(h3);
return OK_7;

Как можно избавиться от таких вещей ?
      CloseHandle(h1);
      CloseHandle(h2);
      CloseHandle(h3);
      return OK_1;

В принципе можно было бы 1 раз в конце написать, а во всех остальных местах делать "goto". Но это как то некрасиво. А писать каждый раз полностью тоже некрасиво, да и запутаешься потом...
Re: Освобождение ресурсов & обработка ошибок
От: _Dreamer Россия  
Дата: 04.08.06 03:40
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

А>Вот такая ситуация


А>Как можно избавиться от таких вещей ?

А>
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>

А>В принципе можно было бы 1 раз в конце написать, а во всех остальных местах делать "goto". Но это как то некрасиво. А писать каждый раз полностью тоже некрасиво, да и запутаешься потом...

а С или С++ ?
если С++ то можно так —
struct handle_holder
{
    HANDLE handle_;

    handle_holder( HANDLE h ) : handle_(h) {}

    bool operator ! () const 
    {
        return (!handle_);
    }

    HANDLE value() const 
    {
        return handle_;
    }

    ~handle_holder()
    {
        CloseHandle( handle_ );
    }
};

// использовать так - 
{
  handle_holder h1( SomeFunc1() );
  if ( !h1 )
    return SOME_ERROR_1;
}


при этом для всех хендлов будет вызван CloseHandle() автоматом при выходе из функции.
Re: Освобождение ресурсов & обработка ошибок
От: Jonathan  
Дата: 04.08.06 03:41
Оценка:
используй идею auto_ptr
"If everything seems under control, you're just not going fast enough"
Re: Освобождение ресурсов & обработка ошибок
От: _Dreamer Россия  
Дата: 04.08.06 03:46
Оценка:
Здравствуйте, Аноним, Вы писали:

вот еще статейку посмотри
Автор(ы): Павел Блудов, Александр Корсуков, Владислав Чистяков
Дата: 09.06.2004
Библиотека классов-оберток для объектов ядра windows.
Re: Освобождение ресурсов & обработка ошибок
От: avs99 Южная Корея  
Дата: 04.08.06 03:46
Оценка:
См. в сторону RAII (resource acquisition is initialization).

class CHandle
{
public:
    CHandle(HANDLE h): m_Handle(h) {};
    ~CHandle() 
    {
        if (m_Handle != NULL) 
             CloseHandle(m_Handle);
    }

      ....  // ну и всякого тут по желанию, HANDLE operator() и т.д.
}


CHandle h1( Somefunc1() );
CHandle h2( Somefunc2() );





Здравствуйте, Аноним, Вы писали:

А>Вот такая ситуация

А>
А>HANDLE h1 = Somefunc1();
А>if (h1 == NULL)  return ERROR_CODE;

А>HANDLE h2 = Somefunc2();
А>if (h2 == NULL)  {
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h3 = Somefunc3();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h4 = Somefunc4();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   CloseHandle(h3);
А>   return ERROR_CODE;
А>}

А>if (Condition1)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>}

А>if (Condition2)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_2;
А>}
А>//...
А>CloseHandle(h1);
А>CloseHandle(h2);
А>CloseHandle(h3);
А>return OK_7;
А>

А>Как можно избавиться от таких вещей ?
А>
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>

А>В принципе можно было бы 1 раз в конце написать, а во всех остальных местах делать "goto". Но это как то некрасиво. А писать каждый раз полностью тоже некрасиво, да и запутаешься потом...
Re[2]: Освобождение ресурсов & обработка ошибок
От: Аноним  
Дата: 04.08.06 04:15
Оценка:
Здравствуйте, _Dreamer, Вы писали:

_D>а С или С++ ?

_D>если С++ то можно так -
_D>
_D>struct handle_holder
_D>{
_D>    HANDLE handle_;

_D>    handle_holder( HANDLE h ) : handle_(h) {}

_D>    bool operator ! () const 
_D>    {
_D>        return (!handle_);
_D>    }

_D>    HANDLE value() const 
_D>    {
_D>        return handle_;
_D>    }

_D>    ~handle_holder()
_D>    {
_D>        CloseHandle( handle_ );
_D>    }
_D>};

_D>// использовать так - 
_D>{
_D>  handle_holder h1( SomeFunc1() );
_D>  if ( !h1 )
_D>    return SOME_ERROR_1;
_D>}
_D>


_D>при этом для всех хендлов будет вызван CloseHandle() автоматом при выходе из функции.

Пасиб, понял.
Re: Освобождение ресурсов & обработка ошибок
От: sokel Россия  
Дата: 04.08.06 07:02
Оценка:
Можно так:

HANDLE h1, h2, h3, h4;
h1 = h2 = h3 = h4 = NULL;
int ret = ERROR_CODE;
if((h1 = SomeFunc1()) && (h2 = SomeFunc2()) && (h3 = SomeFunc3()) && (h4 = SomeFunc4()))
{
    if        (Condition1)  { DoSomething(); ret = OK_1; }
    else if    (Condition2)  { DoSomething(); ret = OK_2; }
    //..
    else ret = OK_7;
}
if(h1)CloseHandle(h1);
if(h2)CloseHandle(h2);
if(h3)CloseHandle(h3);
if(h4)CloseHandle(h4);
return ret;
Re: Освобождение ресурсов & обработка ошибок
От: Testus  
Дата: 04.08.06 07:12
Оценка:
Можно упростить это всё дело с использованием обработчика исключительных ситуаций
__try
{
//делать "опасные" действия
}
__except
{
//тут можно обработать ошибки
}


P.S. Винда такое часто использует
Glück auf
Re[2]: Освобождение ресурсов & обработка ошибок
От: Roman Odaisky Украина  
Дата: 04.08.06 07:41
Оценка:
Здравствуйте, Testus, Вы писали:

T>Можно упростить это всё дело с использованием обработчика исключительных ситуаций

T>__try
T>__except

А try/catch???
До последнего не верил в пирамиду Лебедева.
Re[2]: Освобождение ресурсов & обработка ошибок
От: Left2 Украина  
Дата: 04.08.06 08:07
Оценка:
Настоятельно рекомендовал бы юзать такие конструкции как можно реже.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Освобождение ресурсов & обработка ошибок
От: Testus  
Дата: 04.08.06 08:45
Оценка:
Здравствуйте, Left2, Вы писали:

L>Настоятельно рекомендовал бы юзать такие конструкции как можно реже.


Почему?
Glück auf
Re[3]: Освобождение ресурсов & обработка ошибок
От: Testus  
Дата: 04.08.06 09:04
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

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


T>>Можно упростить это всё дело с использованием обработчика исключительных ситуаций

T>>__try
T>>__except

А у __try/__except есть еще удобная __finally и __leave, хотя можно и try/catch
Glück auf
Re[4]: Освобождение ресурсов & обработка ошибок
От: Left2 Украина  
Дата: 04.08.06 09:13
Оценка:
T>Почему?

1. Непереносимость
2. Невозможность использования внутри __try __catch хоть сколько-либо С++ кода (нет возможности создавать классы с конструкторами-деструкторами.
3. Надо аккуратно сопрягать __try/__catch с родным для С++ try/catch

Вообщем, никаких плюсов по сравнению с try/catch я не вижу кроме тех случаев когда действительно нужно работать с Windows SEH (задача довольно редкая).

Ну и вообще — использовать try/catch для очистки ресуров идеологически неверно, для этого RAII придумали.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Освобождение ресурсов & обработка ошибок
От: vvotan Россия  
Дата: 05.08.06 13:58
Оценка:
Здравствуйте, Testus, Вы писали:

T>Можно упростить это всё дело с использованием обработчика исключительных ситуаций


Я бы даже сказал:

DWORD Funcarama4() {

   // IMPORTANT: Initialize all variables to assume failure.
   HANDLE hFile = INVALID_HANDLE_VALUE;
   PVOID pvBuf = NULL;

   // Assume that the function will not execute successfully.
   BOOL fFunctionOk = FALSE;

   __try { 
      DWORD dwNumBytesRead;
      BOOL fOk;

      hFile = CreateFile("SOMEDATA.DAT", GENERIC_READ,
         FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
      if (hFile == INVALID_HANDLE_VALUE) {
         __leave;
      }

      pvBuf = VirtualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);

      if (pvBuf == NULL) {
         __leave;
      }

      fOk = ReadFile(hFile, pvBuf, 1024, &dwNumBytesRead, NULL);
      if (!fOk || (dwNumBytesRead == 0)) {
         __leave;
      }

      // Do some calculation on the data.

      

      // Indicate that the entire function executed successfully.
      fFunctionOk = TRUE;
   }
   __finally {
      // Clean up all the resources.
      if (pvBuf != NULL)
         VirtualFree(pvBuf, MEM_RELEASE | MEM_DECOMMIT);
      if (hFile != INVALID_HANDLE_VALUE)
         CloseHandle(hFile);
   }
   // Continue processing.
   return(fFunctionOk);
}


(с) Рихтер
--
Sergey Chadov

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Освобождение ресурсов & обработка ошибок
От: vvotan Россия  
Дата: 05.08.06 13:58
Оценка:
Здравствуйте, Left2, Вы писали:

T>>Почему?


L>1. Непереносимость

Это по сравнению с CloseHandle?

L>2. Невозможность использования внутри __try __catch хоть сколько-либо С++ кода (нет возможности создавать классы с конструкторами-деструкторами.

Это да. Но если там С++ кода все равно нет, то никто не мешает воспользоваться SEH.
В приведенном примере типичный код общения с винапи(так и вижу открытие файлмаппинга), возможно находящийся внутри С++ класса. В таком случае ничего страшного от использования SEH нету.

L>3. Надо аккуратно сопрягать __try/__catch с родным для С++ try/catch

Это тоже да, в типичном с-подобном коде никаких try/catch нету.

L>Вообщем, никаких плюсов по сравнению с try/catch я не вижу


__finally

L>Ну и вообще — использовать try/catch для очистки ресуров идеологически неверно, для этого RAII придумали.

Задолбешься каждый хендл в класс оборачивать. Для небольшого проекта SEH может оказаться проще.
--
Sergey Chadov

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Освобождение ресурсов & обработка ошибок
От: Slava Antonov Россия http://deadbeef.narod.ru
Дата: 05.08.06 14:59
Оценка: +1
Hello vvotan, you wrote:

> Задолбешься каждый хендл в класс оборачивать. Для небольшого проекта SEH может оказаться проще.


А если шаблон сделать? Например, с двумя параметрами: тип дескриптора и указатель на функцию для освобождения ресурса.

--
Всего хорошего, Слава
ICQ: 197577902
Posted via RSDN NNTP Server 2.0
Re[7]: Освобождение ресурсов & обработка ошибок
От: vvotan Россия  
Дата: 05.08.06 17:06
Оценка:
Здравствуйте, Slava Antonov, Вы писали:

SA>Hello vvotan, you wrote:


>> Задолбешься каждый хендл в класс оборачивать. Для небольшого проекта SEH может оказаться проще.


SA>А если шаблон сделать? Например, с двумя параметрами: тип дескриптора и указатель на функцию для освобождения ресурса.


Можно и так
--
Sergey Chadov

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Освобождение ресурсов & обработка ошибок
От: k732  
Дата: 05.08.06 17:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вот такая ситуация

А>
А>HANDLE h1 = Somefunc1();
А>if (h1 == NULL)  return ERROR_CODE;

А>HANDLE h2 = Somefunc2();
А>if (h2 == NULL)  {
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h3 = Somefunc3();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h4 = Somefunc4();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   CloseHandle(h3);
А>   return ERROR_CODE;
А>}

А>if (Condition1)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>}

А>if (Condition2)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_2;
А>}
А>//...
А>CloseHandle(h1);
А>CloseHandle(h2);
А>CloseHandle(h3);
А>return OK_7;
А>

А>Как можно избавиться от таких вещей ?
А>
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>

А>В принципе можно было бы 1 раз в конце написать, а во всех остальных местах делать "goto". Но это как то некрасиво. А писать каждый раз полностью тоже некрасиво, да и запутаешься потом...



#include <boost\shared_ptr.hpp>

class Handle {
private:
    boost::shared_ptr<void> m_handle;

public :
    Handle ()
    {
        m_handle = CreateHandleFunction(...);
        if (m_handle == INVALID_HANDLE_VALUE)
        {
            throw ...;
        }
    }
    Handle (HANDLE handle) : m_handle (handle, CloseHandle) {;}
    operator HANDLE () { return m_handle.get(); }
};


void main (void)
{
    try
    {
        Handle h = Somefunc2(...);
        ...
    }
    catch (...)
    {
        ...
    }
}
Re[2]: Освобождение ресурсов & обработка ошибок
От: k732  
Дата: 05.08.06 17:52
Оценка:
Здравствуйте, k732, Вы писали:

K>Здравствуйте, Аноним, Вы писали:

немного ошибся


#include <boost\shared_ptr.hpp>

class Handle {
private:
    boost::shared_ptr<void> m_handle;

public :
    Handle ()
    {

        HANDLE handle = CreateHandleFunction(...);
        if (handle == INVALID_HANDLE_VALUE)
        {
            throw ...;
        }
        m_handle.reset (handle, CloseHandle);
    }
    Handle (HANDLE handle) : m_handle (handle, CloseHandle) {;}
    operator HANDLE () { return m_handle.get(); }
};


void main (void)
{
    try
    {
        Handle h = Somefunc2(...);
        ...
    }
    catch (...)
    {
        ...
    }
}
Re: Освобождение ресурсов & обработка ошибок
От: k732  
Дата: 07.08.06 08:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вот такая ситуация

А>
А>HANDLE h1 = Somefunc1();
А>if (h1 == NULL)  return ERROR_CODE;

А>HANDLE h2 = Somefunc2();
А>if (h2 == NULL)  {
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h3 = Somefunc3();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   return ERROR_CODE;
А>}

А>HANDLE h4 = Somefunc4();

А>if (h3 == NULL)  {
А>   CloseHandle(h1);
А>   CloseHandle(h2);
А>   CloseHandle(h3);
А>   return ERROR_CODE;
А>}

А>if (Condition1)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>}

А>if (Condition2)  {
А>      DoSomething();
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_2;
А>}
А>//...
А>CloseHandle(h1);
А>CloseHandle(h2);
А>CloseHandle(h3);
А>return OK_7;
А>

А>Как можно избавиться от таких вещей ?
А>
А>      CloseHandle(h1);
А>      CloseHandle(h2);
А>      CloseHandle(h3);
А>      return OK_1;
А>

А>В принципе можно было бы 1 раз в конце написать, а во всех остальных местах делать "goto". Но это как то некрасиво. А писать каждый раз полностью тоже некрасиво, да и запутаешься потом...


обернуть все это (я уже где-то приводил этот пример)

#include <boost\shared_ptr.hpp>

class Handle {
private:
    boost::shared_ptr<void> m_handle;

public :
    Handle ()
    {

        HANDLE handle = CreateHandleFunction(...);
        if (handle == INVALID_HANDLE_VALUE)
        {
            throw ...;
        }
        m_handle.reset (handle, CloseHandle);
    }
    Handle (HANDLE handle) : m_handle (handle, CloseHandle) {;}
    operator HANDLE () { return m_handle.get(); }
};


void main (void)
{
    try
    {
        Handle h = Somefunc(...);
        ...
    }
    catch (...)
    {
        ...
    }
}


или просто, нужно закрыть копирующие конструкторы

class Handle {
private:
    HANDLE m_handle;

    Handle (const Handle&);
    Handle& operator = (const Handle&);

public :
    Handle ()
    {

        m_handle = CreateHandleFunction(...);
        if (m_handle == INVALID_HANDLE_VALUE)
        {
            throw ...;
        }
    }
    ~Handle () { CloseHandle(m_handle); }
    Handle (HANDLE handle) : m_handle (handle) {;}
    operator HANDLE () { return m_handle; }
};
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.