コード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#include <Windows.h> #include <iostream> #include <memory> #pragma comment(lib, "Shell32.lib") using namespace std; class MyClass { public: MyClass() { cout << "ctor" << endl; } ~MyClass() { cout << "dtor" << endl; } }; int main() { { // basic unique_ptr<MyClass> p1(new MyClass); unique_ptr<MyClass> p2 = make_unique<MyClass>(); } { int* pI = new int(); unique_ptr<int> up(pI); } // array { unique_ptr<char[]> p(new char[100]); strcpy(p.get(), "Hello World!"); cout << p << endl; } // malloc and free { unique_ptr<char, void (__cdecl*)(void*)> p(static_cast<char*>(malloc(100)), free); strcpy(p.get(), "malloc world!"); cout << p << endl; } // malloc and free 2 { unique_ptr<wchar_t, std::function<void(void*)>> p(_tcsdup(L"abc"), free); cout << p << endl; } // C file { unique_ptr<FILE, int(__cdecl*)(FILE*)> file(fopen("myfile.txt","r"),fclose); // do something } // Win32 { int argc; unique_ptr<LPWSTR, HLOCAL(WINAPI *)(HLOCAL)> arg(::CommandLineToArgvW(L"aaa.exe a b \"c d e f\"", &argc), ::LocalFree); for(int i=0 ; i < argc ;++i) { wcout << i << L":" << arg.get()[i] << endl; } } return 0; } |
基本
unique_ptrは渡されたポインタの所有権を保持する。つまりこのポインタを解放するのはunique_ptrの役割である。ポインタが破棄されるのはunique_ptrが破棄される時かreset()によって他のポインタがセットされる時である。よってget()で取得したポインタを破棄したり、他のスマートポインタに渡してはいけない。
std::move
unique_ptrをunique_prtにコピーというか移動するにはstd::moveを使わなくてはならない。
カスタムデリート
unique_ptrの第2テンプレート引数にはデリーターを指定する。この関数は破棄される際にポインタが渡される。デフォルトはdeleteなので作成時にnewで作ったオブジェクトを渡す。しかしnewで作れないオブジェクトはたくさんあるのでコード例のようにカスタムデリーターを指定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ unique_ptr<MyClass> p = make_unique<MyClass>(); unique_ptr<MyClass> q(std::move(p)); std::cout << "p = " << (p ? "not null" : "null") << std::endl; } std::cout << "======================" << std::endl; { unique_ptr<MyClass> p; p.reset(new MyClass); // OK, previous instance will be freed p.reset(new MyClass); } |
std::function
カスタムデリーターはポインタ1つを引数に取る関数オブジェクトのを指定しなければならない。呼び出し規約がデフォルトと違う場合はそれも指定しないといけないのでややこしい。この場合はstd::functionを使えば呼び出し規約を気にしなくてもいい。
開放関数が引数を2つ取るなどの場合はラムダやファンクタを指定することになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include <Windows.h> #include <iostream> #include <memory> #include <functional> #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "user32.lib") using namespace std; class MyClass { public: MyClass() { cout << "ctor" << endl; } ~MyClass() { cout << "dtor" << endl; } }; int main() { // malloc and free { unique_ptr<char, std::function<void(void*)>> p(static_cast<char*>(malloc(100)), std::function<void(void*)>(free)); strcpy(p.get(), "malloc world!"); cout << p.get() << endl; } // C file { unique_ptr<FILE, std::function<int(FILE*)>> file(fopen("myfile.txt","r"),std::function<int(FILE*)>(fclose)); // do something } // Win32 { int argc; unique_ptr<LPWSTR, std::function<HLOCAL(HLOCAL)>> arg(::CommandLineToArgvW(L"aaa.exe a b \"c d e f\"", &argc), std::function<HLOCAL(HLOCAL)>(::LocalFree)); for(int i=0 ; i < argc ;++i) { wcout << i << L":" << arg.get()[i] << endl; } } // lambda { // OpenClipboard returns BOOL // Treat BOOL as void* unique_ptr<void, std::function<void(void*)>> clip(reinterpret_cast<void*>(::OpenClipboard(nullptr)), std::function<void(void*)>([](void*p) { if(p) CloseClipboard(); } ) ); } return 0; } |