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

[上一篇](https://dev.mukyu.tw/way-to-cpp-3-std-unique-ptr)

# 目標: 自動關閉檔案

現在來想一想，怎麼做到自動關閉檔案，以 `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 的函數。會在下幾章說明。
