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

·

1 min read

上一篇

目標: 自動關閉檔案

現在來想一想,怎麼做到自動關閉檔案,以 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::bindlambda 基本上都是形成一個 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 的函數。會在下幾章說明。