C ++とスマートポインタの例のshared_ptrを使用して

shared_ptrのは、スマートポインタクラスC ++ 11は、メモリリークとダングリングポインタの問題を解消する助けに提供しています。

1、shared_ptrの特長

:各2つのポインタを持っている内部のshared_ptrのはオブジェクト
1、オブジェクトへのポインタを。
図2に示すように、カウントデータ参照ポインタを制御します。

参照カウントの役割:
1、新しいオブジェクトポインタのshared_ptrが関連付けられ、そのコンストラクタで、このポインタに関連付けられた参照カウントがインクリメントされます。
図2に示すように、任意のshared_ptrオブジェクトが範囲外になると、そのデストラクタ、その関連付け参照カウントポインタ。参照カウントが0になる場合は、無他のshared_ptrが、その場合には、それはメモリを削除するには削除機能を使用して、このメモリに関連付けられているオブジェクト。

2、shared_ptrのオブジェクトを作成します

shared_ptrのオブジェクトは、元のポインタを使用して作成しました

std::shared_ptr<int> p1(new int());

:上記のコード行は、ヒープ上の2つのメモリ作成
(1)店舗INTを。
(2)メモリの参照カウント、この追加メモリの回数管理のshared_ptrオブジェクトは、最初のカウントは1であろう。

(1)は、オブジェクトの参照カウントを確認しshared_ptrの

use_count();

(2)空のshared_ptrオブジェクトを作成します

shared_ptrのコンストラクタのパラメータは型に明示的であるため、それがのstd :: shared_ptrのP1 =新しいint型のようではありません();暗黙の呼び出しそれコンストラクタ。新しいのshared_ptrオブジェクトを作成するための最良の方法は、STDを使用することです:: make_shared:

std::shared_ptr<int> p1 = std::make_shared<int>();

std ::唯一の新しいオペレータ割り当てメモリint型のために、メモリを割り当てるための使い捨てのint型のカウントデータオブジェクトと参照をmake_shared。

生ポインタ関連分離(3)

リンク解除のshared_ptrがポインタに関連付けられたオブジェクトに、あなたは()関数をリセットすることができます。
パラメータなしのRESETを():

リセット();

参照カウントは、参照カウントが0になった場合、ポインタが削除され、1減算されます。
)(リセットパラメータを持ちます:

リセット(新しいint型(34));

この場合には、したがって、その参照カウントは再び1となり、内部に新しいポインタをポイントします。
nullptrリセットを使用します。

P1 = nullptr;

shared_ptrの擬似ポインタであり
、通常のポインタとしてのshared_ptr作用、我々は*ことができます- > shared_ptrのオブジェクトと一緒に使用、また、同じような他のshared_ptrオブジェクトと比較することができます。

完全な例

#include <iostream>
#include  <memory> // 需要包含这个头文件

int main()
{
	// 使用 make_shared 创建空对象
	std::shared_ptr<int> sp = std::make_shared<int>();
	*sp = 8;
	std::cout << "sp = " << *sp << std::endl; // 输出8

	// 打印引用个数:1
	std::cout << "sp Ref count = " << sp .use_count() << std::endl;

	// 第2个 shared_ptr 对象指向同一个指针
	std::shared_ptr<int> sp2 (sp );

	// 下面两个输出都是:2
	std::cout << "sp2 Ref count = " <<sp2.use_count() << std::endl;
	std::cout << "sp Ref count = " << sp.use_count() << std::endl;

	// 比较智能指针,p1 等于 p2
	if (sp2== sp) {
		std::cout << "point to same pointer\n";
	}

	std::cout<<"Reset sp"<<std::endl;

	// 无参数调用reset,无关联指针,引用个数为0
	sp.reset();
	std::cout << "spRef Count = " << sp.use_count() << std::endl;
	
	// 带参数调用reset,引用个数为1
	sp.reset(new int(11));
	std::cout << "sp Ref Count = " << sp.use_count() << std::endl;

	// 把对象重置为NULL,引用计数为0
	sp= nullptr;
	std::cout << "sp Ref Count = " << sp.use_count() << std::endl;
	if (!sp) {
		std::cout << "sp is NULL" << std::endl; // 输出
	}
	return 0;
}

3、DELETERデリータカスタム

shared_ptrの範囲外のオブジェクトと、それはデストラクタを呼び出します。そのデストラクタでは、新しい参照カウントが0である場合は、関連元のポインタを削除し、1でカウント数を参照します。
デストラクタ、元の内部ポインタを削除し、デフォルトの呼び出しは()関数を削除します。

ポインタを削除します。

時にはデストラクタで、削除機能は、我々のニーズを満たしていない、あなたはまた、他の処理を追加することもできます。

場合のshared_ptrは、アレイを指すオブジェクト
のstd :: shared_ptrの属(新しいINT [ 12])。

このアプリケーションのような配列は、] [リリースメモリを削除呼び出すが、shared_ptrのデストラクタ削除デフォルトと需要を満たすことができないはずです。

(1)削除のshared_ptrにカスタムフィルタを追加

上記のこの例では、即ち、削除する、そこからコンストラクタ、デストラクタを呼び出し、コンストラクタに渡されたのshared_ptrを、コールバックすることができ

//カスタムデリータ

void delete_me(int* x)
{
	delete[] x;
}
// 构造函数传递自定义删除器指针
std::shared_ptr<int> sp(new int[12],delete_me);

完全な例で見てみましょう:

#include <iostream>
#include <memory>

struct Test
{
    Test() { std::cout << "Test\n";}
    ~Test() { std::cout << "~Test\n";}
};

void deleter(Test* x)
{
    std::cout << "Custom Deleter\n";
    delete[] x;
}

int main()
{
    std::shared_ptr<Test> sp(new Test[3], delete_me);
    return 0;
}

使用ラムダ表現/関数オブジェクトは、次のように削除されます

class DeleteMe
{
	public:
	void operator() (Test* x) {
		std::cout<<"DeleteMe\n";
		delete[] x;
	}
};

// 函数对象作为删除器
std::shared_ptr<Test> sp(new Test[3], DeleteMe());

// Lambda表达式作为删除器
std::shared_ptr<Test> sp1(new Test[3], [&](Test* x){
	std::cout<<"Lambda delete\n";
		delete[] x;
});

通常のポインタの相対的な長所と短所がshared_ptrの:
(1)は、+の欠如- - 、及び[]演算子;
(2)通常のポインタと比較して、唯一のshared_ptr - >、*オペレータ==なし+、 - 、+、 - 、[]および他のオペレータ。

4、NULL検出器

あなたはshared_ptrのオブジェクトを作成するときに任意の値を割り当てられていない、それが空であり、通常のポインタが宇宙ゴミに野生のポインタにスペース対応を割り当てませんし、有用なデータかどうかを判断するために指すことはできませんとき。
ヌルのshared_ptrを検出する方法

std::shared_ptr<Test> test;
if(!test)
	std::cout<<"Yes, testis empty" << std::endl;
if(test== NULL)
	std::cout<<"testis empty" << std::endl;
if(test== nullptr)
	std::cout<<"testis empty" << std::endl;

5つの注意事項のshared_ptrを使用しました:

(1)同じ元の構造ポインタのshared_ptrを使用しないでください

通常の方法のshared_ptr複数のshared_ptrを作成すると、既存のではなく作成したのと同じ生のポインタを使用するよりも、作成を使用することです。
例:

int *num = new int(23);
std::shared_ptr<int> p1(num);

std::shared_ptr<int> p2(p1);  // 正确使用方法
std::shared_ptr<int> p3(num); // 错误方法,重复卸载

あなたは生のポインタを使用する場合、numがP1を作成し、同じ方法でP3を作成するためにリリースが削除num個のメモリを呼び出しますとき、p1はスコープから外れ、numが、現時点ではダングリングポインタになっP3がスコープの外に出たとき、彼は間違っている可能性がありますとき、再び削除。

(2)ポインタスタック構成済みのshared_ptrオブジェクトを使用しません

shared_ptrのデフォルトコンストラクタが構造ので、彼らはまた、ヒープ領域の新しいポインタを使用する必要があり、関連するポインタを削除し、削除するために使用されます。
例:

   int x = 12;
   std::shared_ptr<int> sp(&x);

オブジェクトは、ときのxデストラクタ削除ポインタ&エラーを呼び出すスコープshared_ptrの外に出たとき。

(3)はmake_shared推奨しました

<> shared_ptrのオブジェクトが作成されたのではなく、デフォルトのコンストラクタを使用して作成されます()上記の二つの状況を避けるために、我々はmake_sharedお勧めします。

std::shared_ptr<int> ptr_1 = make_shared<int>();
std::shared_ptr<int> ptr_2 (ptr_1);

(4)慎重な使用のget()関数

手動で削除関数呼び出し前のshared_ptrのデストラクタ場合、また、同様のエラーを引き起こすため)GET(に注意してくださいさらには、shared_ptrの関連元の関数ポインタを取得します。

公開された43元の記事 ウォンの賞賛9 ビュー2649

おすすめ

転載: blog.csdn.net/x879014419/article/details/105272436