web-dev-qa-db-ja.com

std :: unique_ptrの宣言方法とその使用方法

std::unique_ptrの仕組みを理解しようとしていますが、そのために this documentを見つけました。著者は次の例から始めます。

#include <utility>  //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();

私を混乱させているのは、この行の

unique_ptr<int> uptr (new int(3));

整数を引数として(丸括弧の間)、ここで使用します

unique_ptr<double> uptr2 (pd);

引数としてポインターを使用しました。違いはありますか?

また、この方法で宣言されたポインターが、「通常の」方法で宣言されたポインターとどのように異なるかは、私には明らかではありません。

71
Roman

unique_ptr<T>のコンストラクターは、T型のオブジェクトへの生のポインターを受け入れます(したがって、T*を受け入れます)。

最初の例:

unique_ptr<int> uptr (new int(3));

2番目の例では、ポインターはnew式の結果です。

unique_ptr<double> uptr2 (pd);

ポインターはpd変数に格納されます。

概念的には何も変わりません(生のポインタからunique_ptrを構築します)が、2番目のアプローチは、たとえば次のことを可能にするため、潜在的に危険です。

unique_ptr<double> uptr2 (pd);
// ...
unique_ptr<double> uptr3 (pd);

したがって、同じオブジェクトを効果的にカプセル化するtwoユニークポインターを持つ(つまりniqueポインターのセマンティクスに違反する)。

これが、可能な場合、一意のポインターを作成する最初の形式の方が優れている理由です。 C++ 14では次のことができることに注意してください。

unique_ptr<int> p = make_unique<int>(42);

どちらがより明確で安全です。今、あなたのこの疑いについて:

また、この方法で宣言されたポインターが、「通常の」方法で宣言されたポインターとどのように異なるかは、私には明らかではありません。

スマートポインターは、オブジェクトの所有権をモデル化し、そのオブジェクトへの最後の(スマートで所有している)ポインターが範囲外になったときに、ポイントされたオブジェクトを自動的に破棄します。

このように、動的に割り当てられたオブジェクトでdeleteを実行することを覚えておく必要はありません-スマートポインターのデストラクタがそれを行います-オブジェクトへの(ダングリング)ポインターを逆参照しないかどうかを心配する必要はありませんすでに破壊されています:

{
    unique_ptr<int> p = make_unique<int>(42);
    // Going out of scope...
}
// I did not leak my integer here! The destructor of unique_ptr called delete

unique_ptrは、一意の所有権をモデル化するスマートポインターです。つまり、プログラム内の任意の時点で、one(所有)ポインターが指すオブジェクトのみになります。そのため、unique_ptrはコピー不可です。

スマートポインターを使用して、準拠する必要のある暗黙の契約を破らない限り、メモリがリークしないという保証があり、オブジェクトの適切な所有権ポリシーが適用されます。生のポインタはこの保証を提供しません。

66
Andy Prowl

Unique_ptrへの割り当ての両方の概念に違いはありません。

int* intPtr = new int(3);
unique_ptr<int> uptr (intPtr);

と類似しています

unique_ptr<int> uptr (new int(3));

ここで、unique_ptrは、uptrによって占有されているスペースを自動的に削除します。


この方法で宣言されたポインターは、「通常の」方法で宣言されたポインターとどのように異なるか。

ヒープスペースに整数を作成する場合(newキーワードまたはmallocを使用)、自分でそのメモリをクリアする必要があります(deleteを使用) =またはfree)。

以下のコードでは、

int* heapInt = new int(5);//initialize int in heap memory
.
.//use heapInt
.
delete heapInt;

ここで、使用が完了したら、deleteheapIntを実行する必要があります。削除されない場合、メモリリークが発生します。


このようなメモリリークを回避するために、unique_ptrが使用されます。unique_ptrは、heapIntがスコープ外に出ると、heapIntが占有するスペースを自動的に削除します。

8
fury.slay

一意のポインターは、スコープ外に出たときに管理するオブジェクトを破壊することが保証されています。 http://en.cppreference.com/w/cpp/memory/unique_ptr

この場合:

unique_ptr<double> uptr2 (pd);

pdは、uptr2が範囲外になると破棄されます。これにより、自動削除によるメモリ管理が容易になります。

ここでunique_ptr<int> uptr (new int(3));の大文字と小文字の違いはありませんが、生のポインタはどの変数にも割り当てられません。

6
fatihk