「std::shared ptr」の版間の差分
提供: C++入門
(ページの作成:「std::shared_ptr とは、C++11で追加された参照カウンタを持ち、リソースが共有できるスマートポインタです。 '''読み方'...」) |
|||
行16: | 行16: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
std::shared_ptr<T> name = std::make_shared<T>(コンストラクタの引数); | std::shared_ptr<T> name = std::make_shared<T>(コンストラクタの引数); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | [[std::shared_ptr]]は、カスタムデリータを利用できます。 | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | std::shared_ptr<FILE> f1( fopen(path, mode), [](FILE *fp){ | ||
+ | cout << __PRETTY_FUNCTION__ << endl; | ||
+ | fclose(fp); }); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
行242: | 行249: | ||
a is 0x2840404c 456 | a is 0x2840404c 456 | ||
b is 0x2840403c 123 | b is 0x2840403c 123 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == カスタムデリータの例 == | ||
+ | === ソースコード std_shared_ptr_custom_deleter1.cpp === | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | #include <iostream> | ||
+ | #include <memory> | ||
+ | #include <cstdlib> | ||
+ | #include <cstdio> | ||
+ | using namespace std; | ||
+ | |||
+ | void my_close(FILE *fp) { | ||
+ | cout << __PRETTY_FUNCTION__ << endl; | ||
+ | fclose(fp); | ||
+ | } | ||
+ | class my_close_class { | ||
+ | public: | ||
+ | void operator() (FILE *fp) { | ||
+ | cout << __PRETTY_FUNCTION__ << endl; | ||
+ | fclose(fp); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | int | ||
+ | main(int argc, char const* argv[]) | ||
+ | { | ||
+ | const char *path = "/tmp/a.txt"; | ||
+ | const char *mode = "r"; | ||
+ | { | ||
+ | // 関数 | ||
+ | std::shared_ptr<FILE> f1( fopen(path, mode), my_close); | ||
+ | } | ||
+ | |||
+ | { | ||
+ | // 関数オブジェクト | ||
+ | std::shared_ptr<FILE> f1( fopen(path, mode), my_close_class()); | ||
+ | } | ||
+ | |||
+ | { | ||
+ | // ラムダ式 | ||
+ | std::shared_ptr<FILE> f1( fopen(path, mode), [](FILE *fp){ | ||
+ | cout << __PRETTY_FUNCTION__ << endl; | ||
+ | fclose(fp); }); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | === コンパイル === | ||
+ | <syntaxhighlight lang="bash"> | ||
+ | g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ | ||
+ | -Wl,-rpath=/usr/local/lib/gcc49 std_shared_ptr_custom_deleter1.cpp \ | ||
+ | -o std_shared_ptr_custom_deleter1 | ||
+ | </syntaxhighlight> | ||
+ | === 実行例 === | ||
+ | <syntaxhighlight lang="bash"> | ||
+ | % ./std_shared_ptr_custom_deleter1 | ||
+ | void my_close(FILE*) | ||
+ | void my_close_class::operator()(FILE*) | ||
+ | main(int, const char**)::<lambda(FILE*)> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
2014年1月3日 (金) 19:01時点における最新版
std::shared_ptr とは、C++11で追加された参照カウンタを持ち、リソースが共有できるスマートポインタです。
読み方
- std::shared_ptr
- えすてぃーでぃー しぇあーど ぴーてぃーあーる
目次
概要
参照カウンタで所有者の数をカウントします。共有が増えるたびに、カウンタが1増やされ、共有が減るたびに-1されます。カウンタが0になった時点で、リソースは解放されます。 参照カウントを持つため、メモリの使用量や管理コストが上がるため、性能面では、生のポインタと比較すれば、劣ります。
基本的な使い方は、以下の通りです。
std::shared_ptr<T> name(リソースの生のポインタ);
メモリの確保の場合には、以下を通りです。
std::shared_ptr<T> name = std::make_shared<T>(コンストラクタの引数);
std::shared_ptrは、カスタムデリータを利用できます。
std::shared_ptr<FILE> f1( fopen(path, mode), [](FILE *fp){ cout << __PRETTY_FUNCTION__ << endl; fclose(fp); });
#include <iostream> #include <memory> using namespace std; int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); cout << a << endl; cout << *a << endl; *a = 456; cout << *a << endl; return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr1.cpp -o std_shared_ptr1
実行例
% ./std_shared_ptr1 0x2840403c 123 456
#include <iostream> #include <memory> using namespace std; class C { private: std::string name_; int age_; public: C(std::string name, int age):name_(name), age_(age) {} virtual ~C() { cout<<__PRETTY_FUNCTION__<<endl; } void doit() { cout<<__PRETTY_FUNCTION__<<endl; } }; int main(int argc, char const* argv[]) { { auto a = std::make_shared<C>("Foo", 123); a->doit(); } // destroy C return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr2.cpp -o std_shared_ptr2
実行例
% ./std_shared_ptr2 void C::doit() virtual C::~C()
関数にポインタを渡す例 get()
#include <iostream> #include <memory> using namespace std; void f(int *p) { } int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); f(a.get()); // ポインタを関数に渡す例 return 0; }
明示的な解放の例 reset()
#include <iostream> #include <memory> using namespace std; int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); a.reset();// 明示的な解放 cout << (a ? "Not reset" : "reset") << endl; // reset と表示される return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr4.cpp -o std_shared_ptr4
実行例
% ./std_shared_ptr4 reset
解放しつつ新しいアドレスと値をセットする例
#include <iostream> #include <memory> using namespace std; int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); cout << a << endl; a.reset(new int(99));// 明示的な解放と再設定 cout << (a ? "set" : "reset") << endl; // set と表示される cout << a << endl; // 最初とは違うアドレスが表示される cout << *a << endl; // 99 が表示される return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr5.cpp -o std_shared_ptr5
実行例
% ./std_shared_ptr5 0x2840403c set 0x28465088 99
参照カウントとオーナーの確認の例
#include <iostream> #include <memory> using namespace std; int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); cout << a.use_count() << endl; // 参照カウントは 1 { auto b = a; // b と共有する cout << "count is " << a.use_count() << endl; // 所有者がaとbなので、a は、uniqueな所有者ではないので、 // not unique と表示される。 cout << (a.unique() ? "a is unique" : "a is not unique") << endl; } // b が解放され、参照カウントが1減る cout << "count is " << a.use_count() << endl; // 所有者は、a しか存在しないので、 unique と表示される。 cout << (a.unique() ? "a is unique" : "a is not unique") << endl; return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr6.cpp -o std_shared_ptr6
実行例
% ./std_shared_ptr6 1 count is 2 a is not unique count is 1 a is unique
std::swapでリソースを交換する例
std::swapでリソースを交換します。
#include <iostream> #include <memory> using namespace std; int main(int argc, char const* argv[]) { auto a = std::make_shared<int>(123); auto b = std::make_shared<int>(456); cout << "a is " << a << " " << *a << endl; cout << "b is " << b << " " << *b << endl; cout << "swap" << endl; std::swap(a,b); cout << "a is " << a << " " << *a << endl; cout << "b is " << b << " " << *b << endl; return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 -pthread std_shared_ptr7.cpp -o std_shared_ptr7
実行例
% ./std_shared_ptr7 a is 0x2840403c 123 b is 0x2840404c 456 swap a is 0x2840404c 456 b is 0x2840403c 123
カスタムデリータの例
#include <iostream> #include <memory> #include <cstdlib> #include <cstdio> using namespace std; void my_close(FILE *fp) { cout << __PRETTY_FUNCTION__ << endl; fclose(fp); } class my_close_class { public: void operator() (FILE *fp) { cout << __PRETTY_FUNCTION__ << endl; fclose(fp); } }; int main(int argc, char const* argv[]) { const char *path = "/tmp/a.txt"; const char *mode = "r"; { // 関数 std::shared_ptr<FILE> f1( fopen(path, mode), my_close); } { // 関数オブジェクト std::shared_ptr<FILE> f1( fopen(path, mode), my_close_class()); } { // ラムダ式 std::shared_ptr<FILE> f1( fopen(path, mode), [](FILE *fp){ cout << __PRETTY_FUNCTION__ << endl; fclose(fp); }); } return 0; }
コンパイル
g++49 -std=c++11 -I/usr/local/lib/gcc49/include/c++/ \ -Wl,-rpath=/usr/local/lib/gcc49 std_shared_ptr_custom_deleter1.cpp \ -o std_shared_ptr_custom_deleter1
実行例
% ./std_shared_ptr_custom_deleter1 void my_close(FILE*) void my_close_class::operator()(FILE*) main(int, const char**)::<lambda(FILE*)>
関連項目
- ポインタ / NULL / nullptr
- スマートポインタ
- std::unique_ptr
- std::shared_ptr
- std::weak_ptr
- std::auto_ptr (非推奨)
- boost::shared_ptr
- boost::scoped_ptr
- boost::weak_ptr
- boost::intrusive_ptr