Всем привет
бывает такой юзкейс что надо форсировать вызов клинера не дожидаясь
его стандартного вызова в деструкторе (в .NET есть похожий метод Close)
но в Loki есть почему то только Dismiss позволяющий забыть про клинер
типичный пример: открываем файл, добавляем в клинер, так, что если произойдет
преждевременный выход из функции то клинер должен закрыть файл,
но если мы дошли до "конца" функции то нам надо форсировать вызов клинера
дабы закрыть файл и после этого например удалить его
вот пример
int _tmain(int argc, _TCHAR* argv[])
{
auto fh = fopen("c:/tes22", "w+");
ScopeGuard g1 = MakeGuard(fclose, fh);
// если преждевременный выход из функции закрыть файл и выйти
// если дошли сюда, удалить файл
auto res = std::remove("c:/tes22");
return 0;
}
но файл не удаляется так как он открыт
а что если добавить virtual к деструктору базового класса
loki/ScopeGuard.h
virtual ~ScopeGuardImplBase()
{}
и добавить вызов Dismiss дабы не быть вызванными повторно во время стандартного вызова деструктора
template <typename J>
void SafeExecute(J& j) throw()
{
if (!j.dismissed_)
{
#ifndef LOKI_SCOPEGUARD_NO_EXCEPTIONS
try
{
j.Execute();
}
catch(...)
{}
#else
j.Execute();
#endif
Dismiss();
}
}
теперь мой пример кода можно переписать так
int _tmain(int argc, _TCHAR* argv[])
{
auto fh = fopen("c:/tes22", "w+");
ScopeGuard g1 = MakeGuard(fclose, fh);
// если преждевременный выход из функции закрыть файл и выйти
// если дошли сюда, удалить файл
g1.~ScopeGuardImplBase();
auto res = std::remove("c:/tes22");
return 0;
}
насколько корректна такая переделка? или можно как то поприличнее?
Использовать scope guard для закрытия файлового дескриптора как-то не комильфо, задействуйте RAII.
А вот для удаления файла на выходе из функции scope guard как раз пригодится.
Если же все-таки использовать scope guard, то в данном случае стоит задействовать два.
ScopeGuard file_remover; // при выходе из области видимости удалит файл
// открываем файл
...
ScopeGuard file_closer; // при выходе из области видимости закроет файл
...
// если преждевременный выход из функции закрыть файл и выйти
file_remover.Dismiss(); // удалять файл не надо
return; // файл будет закрыт, но не удален
...
// обычный выход из функции
return; // файл будет закрыт, затем удален
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>J>int _tmain(int argc, _TCHAR* argv[])
J>{
J> auto fh = fopen("c:/tes22", "w+");
J> {
J> ScopeGuard g1 = MakeGuard(fclose, fh);
J>
J> // если преждевременный выход из функции закрыть файл и выйти
J>
J> }
J> // если дошли сюда, удалить файл, он уже закрыт
J> auto res = std::remove("c:/tes22");
J> return 0;
J>}
J>
просто использовать дополнительную область видимости (выше)
Здравствуйте, jazzer, Вы писали:
J>>J>>int _tmain(int argc, _TCHAR* argv[])
J>>{
J>> auto fh = fopen("c:/tes22", "w+");
J>> {
J>> auto fh = fopen("c:/tes22", "w+");
J>> ScopeGuard g1 = MakeGuard(fclose, fh);
J>>
J>> // если преждевременный выход из функции закрыть файл и выйти
J>>
J>> }
J>> // если дошли сюда, удалить файл, он уже закрыт
J>> auto res = std::remove("c:/tes22");
J>> return 0;
J>>}
J>>
J>просто использовать дополнительную область видимости (выше)
Вот так будет лучше. А то получим висячий дескриптор.
Ну а если таких сценариев больше одного в программе, то следует завести класс-обёртку над файлом.
Возможно, что эта обёртка будет следить и за именем тоже.
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>loki/ScopeGuard.h
J>насколько корректна такая переделка? или можно как то поприличнее?
Может я чего-то не понимаю, но, судя по коду, ничего менять не надо. Надо просто вызвать Dismiss(), а за ним Execute()
int _tmain(int argc, _TCHAR* argv[])
{
auto fh = fopen("c:/tes22", "w+");
ScopeGuard g1 = MakeGuard(fclose, fh);
// если преждевременный выход из функции закрыть файл и выйти
// если дошли сюда, удалить файл
g1.Dismiss();
g1.Execute();
auto res = std::remove("c:/tes22");
return 0;
}