概要
超絶、今更記事。でも意外と入門サイトとかには書いてない気がするw
あると、ラムダ式とデストラクタの役割が理解出来て良い。
現代プログラミングでは当たり前の内容なんですが、C++やっていると知らないと辛いときがたまにあります。
C言語でしか書かれていないコード、C++使っている癖にこのような視点で変更されていないコードも世の中に結構出回っているので、たま~に役立ちます。
std::ifstreamなんかはこの記事のような対策が打たれている(と思われる)ので、このようなことを考える必要はないです。
**「はじめて学ぶC++11入門」**って感じです。
コード
こんなコード数年ぶりに書きましたわ
#include <iostream>
int main()
{
FILE* fpr;
wchar_t buffer[256];
if( _wfopen_s(&fpr, L"C:\\Test.txt", L"r") == 0) {
fwscanf_s(fp, L"%s", &buffer, 256);
wprintf(L"%s", buffer);
fclose(fpr);
return 0;
} else {
wprintf(L"Error");
return 1;
}
}
問題点
-
fcloseは、_wfopen_sが成功したときしか実行されなくて、成功時と失敗時の表記揺れが怖い
-
fcloseと書くことを忘れそう
解決方法
-
fopen, fcloseの対になっている部分は、helperクラスを定義しておき、コンストラクタでfopen、デストラクタでfcloseを実行するように処理をする
-
ラムダ式(std::function)を使って、具体的な処理は移譲する
#include <functional>
#include <iostream>
class IoHelper {
private:
FILE* fpr;
errno_t error;
public:
IoHelper(std::wstring path, std::function<void(FILE*, errno_t)> func) {
error = _wfopen_s(&fpr, path.c_str(), L"r");
func(fpr, error);
}
virtual ~IoHelper() {
if(error == 0 ) {
fclose(fpr);
}
}
};
int main()
{
{
// このように定義すると、IoHelperが存在するローカルスコープの中では、
// fcloseされないが、ローカルスコープから抜けると自動的にfcloseされる。
IoHelper helper(L"C:\\Test.txt", [] (FILE* fp, errno_t error) {
if( error == 0 ) {
wchar_t buffer[256];
fwscanf_s(fp, L"%s", &buffer, 256);
wprintf(L"%s", buffer);
} else {
wprintf(L"Error");
}
});
}
{
// ここではもうfcloseされている
}
return 0;
}
補足
std::ifstream, std::mutexなどは、このような仕組みと似た設計となっています。
わざわざ意図的にcloseやunlockをしなくても使えるのが良い。