SlideShare a Scribd company logo
1 of 28
Download to read offline
unique_ptrにポインタ以外のもの
を持たせるとき
okada(@okdshin)
unique_ptrって?
C++11で登場したスマートポインタ
auto_ptrの完全上位互換
スコープを抜けたら自動でdelete
#include <iostream>
#include <memory> // for unique_ptr
class Widget {
public:
~Widget() { std::cout << "deleted" << std::endl; }
};
int main() {
std::unique_ptr<Widget> wp{new Widget{}};
}
//output:
// deleted
newだ!! 殺せ!!!!
int main() {
//std::unique_ptr<Widget> wp{new Widget{}};
auto wp = std::make_unique<Widget>();
}
※make_uniqueはC++14から登場
unique_ptrは便利
リソースを自動で開放してくれる
効率もデフォルトだとポインタと同程度で悪くない
STLコンテナの要素にできる(もちろんvectorも!)
デリータも設定できる
unique_ptrにデリータを設定
// Widgetのファクトリ関数
decltype(auto) make_widget() {
auto deleter = [](Widget* wp) {
std::cout << "deleter is called" << std::endl;
delete wp;// きちんとdeleteしておく
};
return std::unique_ptr<Widget, decltype(deleter)>{
new Widget{}, std::move(deleter)};
}
int main() {
auto wp = make_widget();
}
//output:
// deleter is called
// deleted
※デリータを設定する場合はmake_uniqueは使えない
unique_ptrからshared_ptrに変換
int main() {
// デリータごとunique_ptrをshared_ptrに変換可能
{
std::shared_ptr<Widget> shared_wp{make_widget()};
}
{
auto wp = make_widget();
std::shared_ptr<Widget> shared_wp{std::move(wp)};
}
}
デリータもきちんと引き継がれる
unique_ptr → shared_ptrは簡単にできるが逆はできない
∴ファクトリ関数の返り値型はshared_ptrではなく
unique_ptrにするのがgood
じゃあ、リソースハンドルが
ポインタじゃなくてもいいんじゃ
ないの?
リソースハンドルがポインタじゃなかったら?
namespace others /*他人のAPI*/ {
int GetHandle() {/*略*/} // リソースハンドルはint型
void ReleaseHandle(int handle) {/*略*/}
}
decltype(auto) make_unique_handle() {
auto deleter = [](int handle) {
others::ReleaseHandle(handle); // deleteの代わりに開放関数を呼ぶ
};
// コンパイルエラー!! GetHandle()の返り値はポインタじゃないよ!!!
return std::unique_ptr<int, decltype(deleter)>(
others::GetHandle(), std::move(deleter));
}
int main() { auto h = make_unique_handle(); }
単に置き換えただけではコンパイルできない
デリータの中でpointer型を指定
namespace others {/*略*/}
// 昔ながらの関数オブジェクトクラス
struct deleter {
using pointer = int; // デフォルトではint*になるのを、intと指定
void operator()(int handle) { others::ReleaseHandle(handle); }
};
decltype(auto) make_unique_handle() {
return std::unique_ptr<int, deleter>(
others::GetHandle(), deleter{});
}
int main() { auto h = make_unique_handle(); }
※ラムダではメンバ型が宣言できないため
関数オブジェクトクラスを使う
やったか……?
やってない
error: invalid operands of types
'int' and 'std::nullptr_t' to binary 'operator!='
if (__ptr != nullptr)
^
intとnullptrの比較ができずコンパイルエラーに
どうしようもない
bool operator!=(int, std::nullptr_t)は宣言できない
bool my::operator!=(int, std::nullptr_t)' must have an argument of
class or enumerated type
bool operator!=(int i, std::nullptr_t n);
^
もしハンドルが組み込み型じゃなくて、ユーザ定義型
だったらできるけど、そもそもなんでハンドルをnullptr
なんかと比較しなくちゃいけないの?
しょうがないので自分で型を書く
class unique_handle {
void safe_release() {
if(handle_ == others::NullHandle) { return; }
others::ReleaseHandle(handle_);
handle_ = others::NullHandle;
}
int handle_;
public:
unique_handle() : handle_(others::GetHandle()) {}
unique_handle(unique_handle&& rhs)
: handle_{others::NullHandle} {
std::swap(handle_, rhs.handle_);
}
decltype(auto) operator=(unique_handle&& rhs) {
safe_release(); std::swap(handle_, rhs.handle_);
return *this;
}
め、めんどくせえーッ!!!
例外安全性は?
ムーブはちゃんと実装できてる?
リソース漏れ本当にしない?
どのハンドルに対しても実装はほとんど同じなのにハ
ンドルごとに毎回書くの?
任意の型のリソースハンドルに
スコープを抜けたら自動で指定し
たデリータを実行してくれて
ムーブできて
標準ライブラリ並に信頼できる
RAIIラッパがほしい!!!!
あります。
N4189 Generic Scope Guard RAII
Wrapper for the Standard Library
unique_resource
unique_reource
C++標準化委員会のペーパーで次期標準ライブラリに加
えることを提案されているライブラリ
unique_ptrの一般化
unique_resourceによる実装
namespace others {/*略*/}
decltype(auto) make_unique_handle() {
return std::experimental::make_unique_resource(
others::GetHandle(), &others::ReleaseHandle);
}
int main() {
auto h1 = make_unique_handle();
auto h2 = make_unique_handle();
auto h3 = make_unique_handle();
h2 = std::move(h3); // move可能 h2の元々のハンドルはリリース
auto h4 = make_unique_handle();
std::cout << h4.get() << std::endl; // 生のハンドルにアクセス
h4.reset(); // 明示的にハンドルをリリース
}
至極簡単に実装できる
「で? unique_resourceは
いつ使えるようになるの?」
「N4189にExample実装があるから
コピペしたら今すぐ使えるよ」
N4189のunique_resourceは
C++14対応コンパイラで使える
C++11でも少し修正すれば使える
まとめ
unique_ptrはデリータをカスタマイズできるが、ポイ
ンタ型のハンドルしか持てない
非ポインタ型ハンドルの自動リソース管理のために
unique_resourceが提案されている
N4189にunique_resourceの実装例があり、コピペした
ら使える
おまけ
std::threadのRAIIラッパ
Effective Modern C++ Item37
std::threadはjoinableの状態でデストラクタが呼ばれると
プログラムを終了させてしまう
int main() {
// tが処理を終える前にデストラクタが呼ばれると実行時エラーが起こる
std::thread t{[](){ std::cout << "hello" << std::endl; }};
}
そのためstd::threadはどのような実行経路でもデストラ
クタが呼ばれる前に非joinable状態にする必要がある
すなわちデストラクタを呼ぶ前にjoinかdetachする
まさにリソース管理の問題
EMC++ Item37における解決法
自分でRAIIクラスを書く
class unique_thread { // EMC++ではThreadRAII
public:
// デストラクト時の動作を指定できる
enum class dtor_action { join, detach };
unique_thread(std::thread&& t, dtor_action a)
: action_{a}, thread_{std::move(t)} {}
~unique_thread() {
if(thread_.joinable()) {
if(action_ == dtor_action::join) {
thread_.join();
}
else {
thread_.detach();
}
}
unique_resourceを使った実装
デリータとしてラムダを渡すだけでOK
enum class unique_thread_dtor_action { join, detach };
template<typename Func>
decltype(auto)
make_unique_thread(Func&& func, unique_thread_dtor_action action) {
return std::experimental::make_unique_resource(
std::thread{std::forward<Func>(func)},
[action](auto& thread) {
if(thread.joinable()) {
if(action == unique_thread_dtor_action::join) {
thread.join();
}
else {
thread.detach();
}
}
});
参考
N4189 Generic Scope Guard and RAII Wrapper for the
Standard Library (Peter Sommerlad & Andrew L.Sandoval
2014)
Effective Modern C++ (Scott Meyers 2015)

More Related Content

What's hot

組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
kikairoya
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
Genya Murakami
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
Genya Murakami
 
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Preferred Networks
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
kiki utagawa
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
MITSUNARI Shigeo
 

What's hot (20)

組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
 
すごいConstたのしく使おう!
すごいConstたのしく使おう!すごいConstたのしく使おう!
すごいConstたのしく使おう!
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
 
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
 
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターン
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
Pythonとパッケージングと私
Pythonとパッケージングと私Pythonとパッケージングと私
Pythonとパッケージングと私
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
 
プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
Javaバイトコード入門
Javaバイトコード入門Javaバイトコード入門
Javaバイトコード入門
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 

Similar to unique_ptrにポインタ以外のものを持たせるとき

C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
yak1ex
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
Akira Takahashi
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
Yasuhiro Ishii
 
Boost.Flyweight
Boost.FlyweightBoost.Flyweight
Boost.Flyweight
gintenlabo
 
プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集
tecopark
 
プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集
tecopark
 

Similar to unique_ptrにポインタ以外のものを持たせるとき (19)

Visual C++で使えるC++11
Visual C++で使えるC++11Visual C++で使えるC++11
Visual C++で使えるC++11
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
 
CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化CUDAを利用したPIV解析の高速化
CUDAを利用したPIV解析の高速化
 
shared_ptr & weak_ptr (ppt 第2版, DL 専用)
shared_ptr & weak_ptr (ppt 第2版, DL 専用)shared_ptr & weak_ptr (ppt 第2版, DL 専用)
shared_ptr & weak_ptr (ppt 第2版, DL 専用)
 
shared_ptr & weak_ptr (ppt 初版, DL 専用)
shared_ptr & weak_ptr (ppt 初版, DL 専用)shared_ptr & weak_ptr (ppt 初版, DL 専用)
shared_ptr & weak_ptr (ppt 初版, DL 専用)
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
 
Emcpp item31
Emcpp item31Emcpp item31
Emcpp item31
 
TensorFlow Lite Delegateとは?
TensorFlow Lite Delegateとは?TensorFlow Lite Delegateとは?
TensorFlow Lite Delegateとは?
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
 
Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512
 
#5:プログラミングの基本
#5:プログラミングの基本#5:プログラミングの基本
#5:プログラミングの基本
 
Emcjp item21
Emcjp item21Emcjp item21
Emcjp item21
 
Boost.Flyweight
Boost.FlyweightBoost.Flyweight
Boost.Flyweight
 
PerlのOOPにおいて、コンストラクタ 内でメンバ関数を呼ぶ方法は?(Perl Beginners #15)
PerlのOOPにおいて、コンストラクタ 内でメンバ関数を呼ぶ方法は?(Perl Beginners #15)PerlのOOPにおいて、コンストラクタ 内でメンバ関数を呼ぶ方法は?(Perl Beginners #15)
PerlのOOPにおいて、コンストラクタ 内でメンバ関数を呼ぶ方法は?(Perl Beginners #15)
 
プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集プログラミングで言いたいこと聞きたいこと集
プログラミングで言いたいこと聞きたいこと集
 
プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集プログラミングで言いたい聞きたいこと集
プログラミングで言いたい聞きたいこと集
 

unique_ptrにポインタ以外のものを持たせるとき