локи клинер, странный юзкейс
От: jyuyjiyuijyu  
Дата: 26.02.15 05:22
Оценка:
Всем привет

бывает такой юзкейс что надо форсировать вызов клинера не дожидаясь
его стандартного вызова в деструкторе (в .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;
}



насколько корректна такая переделка? или можно как то поприличнее?
Re: локи клинер, странный юзкейс
От: VTT http://vtt.to
Дата: 26.02.15 06:14
Оценка:
Использовать scope guard для закрытия файлового дескриптора как-то не комильфо, задействуйте RAII.
А вот для удаления файла на выходе из функции scope guard как раз пригодится.
Если же все-таки использовать scope guard, то в данном случае стоит задействовать два.

ScopeGuard file_remover; // при выходе из области видимости удалит файл

// открываем файл
...
ScopeGuard file_closer; // при выходе из области видимости закроет файл

...
// если преждевременный выход из функции закрыть файл и выйти
file_remover.Dismiss(); // удалять файл не надо
return; // файл будет закрыт, но не удален
...
// обычный выход из функции
return; // файл будет закрыт, затем удален
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 26.02.2015 6:18 VTT . Предыдущая версия .
Re: локи клинер, странный юзкейс
От: jazzer Россия Skype: enerjazzer
Дата: 26.02.15 06:35
Оценка: +3
Здравствуйте, 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 (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: локи клинер, странный юзкейс
От: Кодт Россия  
Дата: 26.02.15 15:46
Оценка:
Здравствуйте, 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>просто использовать дополнительную область видимости (выше)

Вот так будет лучше. А то получим висячий дескриптор.

Ну а если таких сценариев больше одного в программе, то следует завести класс-обёртку над файлом.
Возможно, что эта обёртка будет следить и за именем тоже.
Перекуём баги на фичи!
Re[3]: локи клинер, странный юзкейс
От: jazzer Россия Skype: enerjazzer
Дата: 26.02.15 16:01
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Вот так будет лучше. А то получим висячий дескриптор.


сорри, я не заметил, что он удаляет файл не по fh, а по просто имени
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: локи клинер, странный юзкейс
От: B0FEE664  
Дата: 26.02.15 16:11
Оценка:
Здравствуйте, 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;
}
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.