Boost.Scopeにも実装されているらしい。
https://www.boost.org/doc/libs/1_85_0/libs/scope/doc/html/index.html
ただBoostの導入は面倒なので、今回は有志がGithubで公開しているものを使う。
https://github.com/okdshin/unique_resource
例えば、C++にはstd::unique_ptrがあり、メモリリークを防げる。この時、カスタムデリータを指定すれば、普通のnew/deleteとは異なった破棄処理を行うこともできる。
// ファイルをクローズするデリータ struct MyFileCloser { void operator()(FILE* ptr) const { fclose(ptr); } };
int main() { { // ファイルを開く std::unique_ptr<FILE, MyFileCloser> pfile(fopen("test", "r"), MyFileCloser()); char buffer[1024]; fgets(buffer, sizeof(buffer), pfile.get()); std::cout << buffer << std::endl; // ファイルはスコープを抜けると自動的にクローズされる } }
問題は管理したい参照がポインタでない場合で、unique_ptrではエラーになる。
#include <memory> #include <unordered_map> // リソースはハンドルでアクセス using HANDLE = int; // リソース管理用のコンテナ std::unordered_map<HANDLE, int*> myresource;
// リソースの確保 HANDLE MyNew(size_t size) { HANDLE handle = 0; myresource.insert({ handle,new int[size] }); return handle++; }
// リソースの解放 void MyDelete(HANDLE handle) { delete[] myresource[handle]; myresource.erase(handle); }
struct My_HANDLE_Release { void operator()(HANDLE handle) const { MyDelete(handle); } };
int main() { // エラー MyNew が返す HANDLE はポインタでない std::unique_ptr<HANDLE, My_HANDLE_Release> uptr(MyNew(100), My_HANDLE_Release()); }
以下から、unique_resource.hpp をダウンロード。
https://github.com/okdshin/unique_resource
#include "unique_resource.hpp"
int main() { HANDLE test; { auto unique_handle = std_experimental::make_unique_resource<HANDLE, My_HANDLE_Release>(MyNew(100), My_HANDLE_Release()); test = unique_handle.get(); // リソースを使う int* p = myresource.at(unique_handle.get()); std::cout << "access " << p << std::endl; for (size_t i = 0; i < 100; ++i) { p[i] = i; }
// リソースが解放される
}
// リソースが解放されているかチェック if( myresource.find(test) == myresource.end() ) { std::cout << "リソースは解放されています" << std::endl; } else { std::cout << "リソースは解放されていません" << std::endl; } }