Шаблон для идиомы RAII
От: Basil2 Россия https://starostin.msk.ru
Дата: 28.12.09 15:58
Оценка:
Чисто чтобы не забывать закрывать виндовые хендлы, набросал примитивный шаблон:


template<typename T>
class CallOnScopeLeave
{
   typedef int (__stdcall *func_type)(T); // int & stdcall need for calling Win API
   func_type Func;
   T Param;

public:
   CallOnScopeLeave(func_type func, T par) : Func(func), Param(par) {};
   ~CallOnScopeLeave()
   {
      Func(Param);
   };
};



Используется, понятное дело, так:

HANDLE hFile = CreaterFile(...);
if (hFile == INVALID_HANDLE_VALUE) 
   return;
CallOnScopeLeave<HANDLE>(&CloseHandle, hFile);
// работа с хэндлом...


А вопрос такой. Наверняка эт не я один умный , и такие шаблоны уже существует. Линканите плз какой-нибудь более-менее известный и стандартный. (Без заточки под винду, как у меня, да и вообще хочется посмотреть на "тру" RAII-шаблон )
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: Шаблон для идиомы RAII
От: denisko http://sdeniskos.blogspot.com/
Дата: 28.12.09 16:04
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Чисто чтобы не забывать закрывать виндовые хендлы, набросал примитивный шаблон:


shared_ptr со заданным деструктором?
<Подпись удалена модератором>
Re: Шаблон для идиомы RAII
От: rg45 СССР  
Дата: 28.12.09 16:16
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Чисто чтобы не забывать закрывать виндовые хендлы, набросал примитивный шаблон:


B>
B>template<typename T>
B>class CallOnScopeLeave
B>{
B>   typedef int (__stdcall *func_type)(T); // int & stdcall need for calling Win API
B>   func_type Func;
B>   T Param;
B>public:
B>   CallOnScopeLeave(func_type func, T par) : Func(func), Param(par) {};
B>   ~CallOnScopeLeave()
B>   {
B>      Func(Param);
B>   };
B>};
B>


B>Используется, понятное дело, так:


B>
B>HANDLE hFile = CreaterFile(...);
B>if (hFile == INVALID_HANDLE_VALUE) 
B>   return;
B>CallOnScopeLeave<HANDLE>(&CloseHandle, hFile);
B>// работа с хэндлом...
B>


B>А вопрос такой. Наверняка эт не я один умный , и такие шаблоны уже существует. Линканите плз какой-нибудь более-менее известный и стандартный. (Без заточки под винду, как у меня, да и вообще хочется посмотреть на "тру" RAII-шаблон )


Сыроватый у тебя шаблон получился: CallOnScopeLeave не запрещает создание новых копий объекта, которые при своем уничтожении будут закрывать один и тот же хендл. Чтобы довести дело до логического завершения нужно либо запретить копирование для CallOnScopeLeave, либо корректно организовать подсчет ссылок и выполнять закрытие хендла с разрушением последнего объекта.

А из существующих, пожалуй, наиболее известными являются boost::scoped_ptr (монопольное владение) и boost::shared_ptr (совместное владение).
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Шаблон для идиомы RAII
От: Кодт Россия  
Дата: 28.12.09 17:03
Оценка:
Здравствуйте, denisko, Вы писали:

D>shared_ptr со заданным деструктором?


Только если даннай хэндл является указателем. А что делать с числами? Зверски кастить к void* и обратно?

Лучше написать и отполировать свой велосипед.
Тем более, что не так уж там много нужно для полировки.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[3]: Шаблон для идиомы RAII
От: rusted Беларусь  
Дата: 28.12.09 17:46
Оценка:
Здравствуйте, Кодт, Вы писали:

D>>shared_ptr со заданным деструктором?


К>Только если даннай хэндл является указателем. А что делать с числами? Зверски кастить к void* и обратно?


К>Лучше написать и отполировать свой велосипед.

К>Тем более, что не так уж там много нужно для полировки.

Можно еще через вот такое умбо-юмбо: http://www.revergestudios.com/reblog/index.php?n=ReCode.SharedPtrHandles
Хоть я и не хотел бы столкнуться с таким трюком в рабочем проекте, но сама идея интересная.
Re[3]: Шаблон для идиомы RAII
От: denisko http://sdeniskos.blogspot.com/
Дата: 28.12.09 19:58
Оценка:
Здравствуйте, Кодт, Вы писали:

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


D>>shared_ptr со заданным деструктором?


К>Только если даннай хэндл является указателем. А что делать с числами? Зверски кастить к void* и обратно?


К>Лучше написать и отполировать свой велосипед.

К>Тем более, что не так уж там много нужно для полировки.
Несколько возражений.
1) Семантически любой Хендл является указателем с флагами.Так что совесть зверский каст оправдает.
2) Можно принимать указатель на хендл, который валяется рядом стеке. Вероятность того, что он запорется, а содержимое shared/scoped ptr останется в целости и сохранности стремительно стремится.
3) Автор, судя по стилю, не сильно склонен заморачиваться с спецификацией исключений и explicitamи. А это вторые и третьи грабли после тех, которые укзазал rg45. Если они начнут срабатывать когда кодом будет пользоваться не только он один, его будут бить. Возможно, даже ногами.
<Подпись удалена модератором>
Re[4]: Шаблон для идиомы RAII
От: denisko http://sdeniskos.blogspot.com/
Дата: 28.12.09 20:04
Оценка:
Здравствуйте, rusted, Вы писали:

R>Здравствуйте, Кодт, Вы писали:


D>>>shared_ptr со заданным деструктором?


К>>Только если даннай хэндл является указателем. А что делать с числами? Зверски кастить к void* и обратно?


К>>Лучше написать и отполировать свой велосипед.

К>>Тем более, что не так уж там много нужно для полировки.

R>Можно еще через вот такое умбо-юмбо: http://www.revergestudios.com/reblog/index.php?n=ReCode.SharedPtrHandles

R>Хоть я и не хотел бы столкнуться с таким трюком в рабочем проекте, но сама идея интересная.
Ты не поверишь, это каноническое использование shared_ptr'a.
<Подпись удалена модератором>
Re[5]: Шаблон для идиомы RAII
От: rusted Беларусь  
Дата: 28.12.09 20:45
Оценка:
Здравствуйте, denisko, Вы писали:

R>>Можно еще через вот такое умбо-юмбо: http://www.revergestudios.com/reblog/index.php?n=ReCode.SharedPtrHandles

R>>Хоть я и не хотел бы столкнуться с таким трюком в рабочем проекте, но сама идея интересная.
D>Ты не поверишь, это каноническое использование shared_ptr'a.

С таким каноническим использованием появляется дополнительный уровень косвенности там, где он не нужен, а объем дополнительного кода не намного меньше, чем в случае своего специального маленького велосипедика.
Re[5]: Шаблон для идиомы RAII
От: Тот кто сидит в пруду Россия  
Дата: 28.12.09 21:20
Оценка:
Здравствуйте, denisko, Вы писали:

К>>>Только если даннай хэндл является указателем. А что делать с числами? Зверски кастить к void* и обратно?


К>>>Лучше написать и отполировать свой велосипед.

К>>>Тем более, что не так уж там много нужно для полировки.

R>>Можно еще через вот такое умбо-юмбо: http://www.revergestudios.com/reblog/index.php?n=ReCode.SharedPtrHandles

R>>Хоть я и не хотел бы столкнуться с таким трюком в рабочем проекте, но сама идея интересная.
D>Ты не поверишь, это каноническое использование shared_ptr'a.

Не поверю. В случае с хэндлом исключена ситуация с циклическими ссылками, поэтому не надо предусматривать возможность реализации weak_ptr, поэтому нет необходимости держать shared_count в отдельном блоке памяти. Иными словами, если уж пришла в голову странная идея изваять обертку для хэндлов из смартпойнтера, делать ее лучше не из shared_ptr, a из intrusive_ptr — меньшее количество раз память выделять придется.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: Шаблон для идиомы RAII
От: Xeor Россия  
Дата: 28.12.09 21:45
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Не поверю. В случае с хэндлом исключена ситуация с циклическими ссылками, поэтому не надо предусматривать возможность реализации weak_ptr, поэтому нет необходимости держать shared_count в отдельном блоке памяти.


Борьба с циклическими ссылками — не единственный способ применения weak_ptr. Например есть ещё signals2::slot.track()
Re: Шаблон для идиомы RAII
От: Bell Россия  
Дата: 29.12.09 03:05
Оценка: 5 (2)
Здравствуйте, Basil2, Вы писали:

Например http://www.ddj.com/cpp/184403758
Любите книгу — источник знаний (с) М.Горький
Re[6]: Шаблон для идиомы RAII
От: Юрий Жмеренецкий ICQ 380412032
Дата: 29.12.09 05:01
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

D>>Ты не поверишь, это каноническое использование shared_ptr'a.


ТКС>Не поверю. В случае с хэндлом исключена ситуация с циклическими ссылками, поэтому не надо предусматривать возможность реализации weak_ptr, поэтому нет необходимости держать shared_count в отдельном блоке памяти. Иными словами, если уж пришла в голову странная идея изваять обертку для хэндлов из смартпойнтера, делать ее лучше не из shared_ptr, a из intrusive_ptr — меньшее количество раз память выделять придется.


shared_ptr поддерживает разные экземпляры deleter'a (stateful), тогда как intrusive_ptr — только 'один' (stateless), поэтому сравнивать на лучше/хуже не совсем корректно. Можно посмотреть на unique_ptr из C++0X, у которого есть возможность использования в двух вариантах — статически заданный deleter (один на все объекты), и вариант с ссылкой на него (каждый объект может иметь собственный deleter). Здесь есть реализация.
Re: Шаблон для идиомы RAII
От: jazzer Россия Skype: enerjazzer
Дата: 29.12.09 07:26
Оценка:
Здравствуйте, Basil2, Вы писали:

B>А вопрос такой. Наверняка эт не я один умный , и такие шаблоны уже существует. Линканите плз какой-нибудь более-менее известный и стандартный. (Без заточки под винду, как у меня, да и вообще хочется посмотреть на "тру" RAII-шаблон )


Boost.ScopeExit
http://www.boost.org/libs/scope_exit/doc/html/index.html

Boost.SmartPtr
http://www.boost.org/libs/smart_ptr/sp_techniques.html#on_block_exit
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Шаблон для идиомы RAII
От: denisko http://sdeniskos.blogspot.com/
Дата: 29.12.09 09:00
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:


ТКС>Не поверю.

Написать свой делетер -- это не каноническое использование?


ТКС>В случае с хэндлом исключена ситуация с циклическими ссылками, поэтому не надо предусматривать возможность реализации weak_ptr, поэтому нет ТКС>необходимости держать shared_count в отдельном блоке памяти.

Аппетит приходит во время еды. Вполне вероятна ситуация, в которой надо управлять временем жизни некоторого разделяемого хендла, получить который от системы было довольно затратно. Разумно расширить наш велосипед и на эту область, а не делать новый. Далее, вероятна ситуация, когда вызов метода какого-нибудь объекта в скопе приведет к тому, что защищаемый хендл сохранится внутрях этого объекта. Это ошибка человека, который проектировал объект, но ошибка достаточно трудноуловимая (кто его знает , когда он этот хендл дернет) и, повторюсь, вероятная. Использование shared_ptr позволит такие ошибки словить достаточно просто.
ТКС> делать ее лучш не из shared_ptr, a из intrusive_ptr — меньшее количество раз память выделять придется.
Тут даже соглашусь, с маленькой оговоркой -- "Евреи, не жалейте заварки".
<Подпись удалена модератором>
Re[7]: Шаблон для идиомы RAII
От: Тот кто сидит в пруду Россия  
Дата: 29.12.09 10:06
Оценка: +2
Здравствуйте, denisko, Вы писали:

ТКС>>Не поверю.

D>Написать свой делетер -- это не каноническое использование?

Использовать умный указатель для управления временем жизни сущностей, не имеющих семантики указателя — не каноническое использование.

ТКС>>В случае с хэндлом исключена ситуация с циклическими ссылками, поэтому не надо предусматривать возможность реализации weak_ptr, поэтому нет ТКС>необходимости держать shared_count в отдельном блоке памяти.

D>Аппетит приходит во время еды. Вполне вероятна ситуация, в которой надо управлять временем жизни некоторого разделяемого хендла, получить который от системы было довольно затратно. Разумно расширить наш велосипед и на эту область, а не делать новый. Далее, вероятна ситуация, когда вызов метода какого-нибудь объекта в скопе приведет к тому, что защищаемый хендл сохранится внутрях этого объекта. Это ошибка человека, который проектировал объект, но ошибка достаточно трудноуловимая (кто его знает , когда он этот хендл дернет) и, повторюсь, вероятная. Использование shared_ptr позволит такие ошибки словить достаточно просто.

Код, иллюстрирующий указанную ситуацию, можете предложить? А я потом объясню, как там обойтись без shared_ptr А то софистикой заниматься лениво.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[4]: Шаблон для идиомы RAII
От: Кодт Россия  
Дата: 29.12.09 11:10
Оценка:
Здравствуйте, denisko, Вы писали:

D>1) Семантически любой Хендл является указателем с флагами.Так что совесть зверский каст оправдает.


Необязательно. А если это куки какой-то сессии?
Куки обычно бывают
— указателями
— числами
— UIDами
— строками

В случае GUID сложно кастить его к указателю и обратно — разве что это будет честный указатель на new GUID. Впрочем, "евреи, не жалейте заварки".

D>2) Можно принимать указатель на хендл, который валяется рядом стеке. Вероятность того, что он запорется, а содержимое shared/scoped ptr останется в целости и сохранности стремительно стремится.


Это очевидная ситуация scope guard, так что scoped_ptr / unique_ptr наше всё.
Использование shared_ptr в данном случае избыточно и ошибкоопасно.

D>3) Автор, судя по стилю, не сильно склонен заморачиваться с спецификацией исключений и explicitamи. А это вторые и третьи грабли после тех, которые укзазал rg45. Если они начнут срабатывать когда кодом будет пользоваться не только он один, его будут бить. Возможно, даже ногами.


Но если заморочится, то это и будет та самая необходимая полировка.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[4]: Шаблон для идиомы RAII
От: Basil2 Россия https://starostin.msk.ru
Дата: 29.12.09 12:02
Оценка:
Здравствуйте, denisko, Вы писали:

D>3) Автор, судя по стилю, не сильно склонен заморачиваться с спецификацией исключений и explicitamи. А это вторые и третьи грабли после тех, которые укзазал rg45. Если они начнут срабатывать когда кодом будет пользоваться не только он один, его будут бить. Возможно, даже ногами.


Хм, а зачем там спецификация исключений и explicit?!

Исключения не предполагаются; "throw()" скорее штука вредная; explicit имеет смысл для конструктора с одним аргументом.
Разве что запретить копирование стоит...
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Шаблон для идиомы RAII
От: Basil2 Россия https://starostin.msk.ru
Дата: 29.12.09 12:05
Оценка:
Здравствуйте, rg45, Вы писали:

R>А из существующих, пожалуй, наиболее известными являются boost::scoped_ptr (монопольное владение) и boost::shared_ptr (совместное владение).


Эти-то понятное дело. Но мой взгляд это форменное извращение — пихать в указатель, пусть и умный, объект указателем не являющийся, да еще и с дополнительной обкладкой в виде user-defined делетера. Я предполагал, что просто существует аналог моего шаблона, только отполированный (я, например, как ты справедливо заметил, не прикрутил запрет копирования).
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Шаблон для идиомы RAII
От: Basil2 Россия https://starostin.msk.ru
Дата: 29.12.09 12:21
Оценка:
Здравствуйте, jazzer, Вы писали:

B>>А вопрос такой. Наверняка эт не я один умный , и такие шаблоны уже существует. Линканите плз какой-нибудь более-менее известный и стандартный. (Без заточки под винду, как у меня, да и вообще хочется посмотреть на "тру" RAII-шаблон )


J>Boost.ScopeExit

J>http://www.boost.org/libs/scope_exit/doc/html/index.html

Дык я, собственно, как на ScopeExit посмотрел, так сразу и понял что надо делать свое

ScopeExit некрасив, использует макросы и генерит скрытый код. А мне нужно тупо вызвать CloseHandle() по окончанию блока, и все. Я и сделал, фактически, тот же ScopeExit, но для _одной_ функции и потому куда как более простой. Однако мой шаблон заточен именно под виндовый CloseHandle(). В частности, в нем даже прописано что функция возвращает int (т.е. виндовый BOOL), т.к. именно это CloseHandle() и возвращает. Т.е. как минимум для универсальности надо добавить в параметры шаблона возвращаемое значение, как-то избавиться от __stdcall (или не надо?), запретить копирование.

Мне казалось, что кто-нибудь это уже проделал...
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: Шаблон для идиомы RAII
От: Кодт Россия  
Дата: 29.12.09 14:51
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Я предполагал, что просто существует аналог моего шаблона, только отполированный (я, например, как ты справедливо заметил, не прикрутил запрет копирования).


Существуют, конечно, и даже в public domain, на RSDN порыться если... Каждый core programmer просто обязан написать такую штуку.
(Только мне, если честно, сейчас не до грибов — искать. Помню, что уже не единожды было. Да и сам писал, с разной степенью кудрявости).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.