Way to C++: 4. Auto close (雜)
目標: 自動關閉檔案
現在來想一想,怎麼做到自動關閉檔案,以 FILE*
為基礎。這篇有一些假設性的想法,主要是熟悉更多語法。
std::unique_ptr
unique_ptr 就有提供自定刪除子,所以我們可以這樣寫:
std::unique_ptr<FILE*> fp(fopen(filename), [](FILE* fp){
if (fp == NULL) return;
fclose(fp);
});
在不需要考慮 fopen
開檔案失敗 (但通常要考慮,這只是假設,提供一個想法),可以寫的更簡潔:
std::unique_ptr<FILE*> fp(fopen(filename), fclose);
std::unique_ptr
會在銷毀時呼叫使用者自訂的 Deletor
,就會自動刪除檔案。
defer
c++ 並沒有提供 defer 的語法,所以我們自己做一個 class:
struct Defer {
public:
Defer(std::function<void()>&& func): func_(std::move(func)) {}
Defer(const std::function<void()>& func): func_(func) {}
Defer(Defer&&) = delete;
Defer(const Defer&) = delete;
Defer& operator=(Defer&&) = delete;
Defer& operator=(const Defer&) = delete;
~Defer() { func_();}
private:
std::function<void()> func_;
};
由於 std::function
可以隱性 (implicit) 的使用 callable object 或 function pointer 初始化,我們可以很方便的使用( std::bind
和 lambda
基本上都是形成一個 callable object):
int func2() {
printf("gg\n");
return 0;
}
int main() {
printf("1\n");
Defer defer1([](){printf("defer func\n");});
Defer defer2(std::bind(printf, "bind\n"));
Defer defer3(func2);
printf("3\n");
return 0;
}
假如,我們希望其實 Defer 初始化直接吃一個參數去初始化 std::function,則可以這樣寫:
struct Defer {
public:
template<typename T>
Defer(const T& param): func_(param) {}
template<typename T>
Defer(T&& param): func_(std::forward<T>(param)) {}
Defer(Defer&&) = delete;
Defer(const Defer&) = delete;
Defer& operator=(Defer&&) = delete;
Defer& operator=(const Defer&) = delete;
~Defer() { func_();}
private:
std::function<void()> func_;
};
其中 T&& 是 Universal Reference (或稱 Forward Reference) , std::forward 則是應對 Forward Reference 的函數。會在下幾章說明。