Skip to content

Way to C++: 4. Auto close (雜) ​

上一篇

目標: 自動關閉檔案 ​

現在來想一想,怎麼做到自動關閉檔案,以 FILE* 為基礎。這篇有一些假設性的想法,主要是熟悉更多語法。

std::unique_ptr ​

unique_ptr 就有提供自定刪除子,所以我們可以這樣寫:

cpp
std::unique_ptr<FILE*> fp(fopen(filename), [](FILE* fp){
   if (fp == NULL) return;
   fclose(fp);
});

在不需要考慮 fopen 開檔案失敗 (但通常要考慮,這只是假設,提供一個想法),可以寫的更簡潔:

cpp
std::unique_ptr<FILE*> fp(fopen(filename), fclose);

std::unique_ptr 會在銷毀時呼叫使用者自訂的 Deletor ,就會自動刪除檔案。

defer ​

c++ 並沒有提供 defer 的語法,所以我們自己做一個 class:

cpp
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):

cpp
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,則可以這樣寫:

cpp
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 的函數。會在下幾章說明。

Changelog

Just observe 👀