MyUtils

View on GitHub

C++ デストラクタによる安全なリソース解放について

 //
 // FileHandle.h
 //
 #ifndef __FileHandle_H__
 #define __FileHandle_H__

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

class FileHandle {
public:
    // public member functions
    // 🌟コンストラクタ(ここでfileをopenする。)
    FileHandle(const char *filepath);
    // 🌟デストラクタ(ここでcloseする。)
    virtual ~FileHandle();

    // 🌟int として参照されるとき呼ばれるメソッド
    virtual operator int(void);
protected:
    // member variable
    // 🌟ファイルディスクリプタを保存するメンバ変数
    int fd;
};

#endif
//🌟コンストラクタ
FileHandle::FileHandle(const char *filepath)
{
    fd = safeopen(filepath);
    //ファイルディスクリプタを保存
}
// デストラクタ
FileHandle::~FileHandle()
{
    // ファイルディスクリプタが-1でない時、closeする。
    // (safeopenで失敗した時 -1を返す)
    if(fd!=-1) close(fd);

    /* 🌟 以下のような使い方ができる。
    FileHandle fh("Test.txt");  ← FileHandle クラスのインスタンスを生成
    if(fh==-1) {
        printf("file open error\n");
        return;
    }
    */
}

// int型で参照した場合のop関数
FileHandle::operator int(void)
{
    // ファイルディスクリプタをそのまま返す。
    return fd;
}

static int safeopen(const char *filepath)
// 🌟安全にファイルをオープンする関数
{
    struct stat lst, fst;
    int fd;

    if (lstat(filepath, &lst) != 0) return -1;
    if (!S_ISREG(lst.st_mode)) return -1;
    fd = open(filepath, O_RDWR, 0);

    if (fd < 0) return -1;

    if (fstat(fd, &fst) != 0) {
       close(fd);
       return -1;
    }

    if (lst.st_ino != fst.st_ino || lst.st_dev != fst.st_dev) {
       close(fd);
       return -1;
    }
    return fd;
}