「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); });

std::shared_ptrの作り方の例

ソースコード std_shared_ptr1.cpp

#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

std::shared_ptrとクラスの例

ソースコード std_shared_ptr2.cpp

#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()

ソースコード std_shared_ptr4.cpp

#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

解放しつつ新しいアドレスと値をセットする例

ソースコード std_shared_ptr5.cpp

#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

参照カウントとオーナーの確認の例

ソースコード std_shared_ptr6.cpp

#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でリソースを交換します。

ソースコード std_shared_ptr7.cpp

#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

カスタムデリータの例

ソースコード std_shared_ptr_custom_deleter1.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;
}

コンパイル

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*)>

関連項目