std :: unique_ptrを宣言する方法とその用途は何ですか?


95

私はどのようにstd::unique_ptr機能するかを理解しようとし、そのためにこのドキュメントを見つけました。著者は次の例から始めます。

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

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

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


13
new int(3)newへのポインタとint同じようpdに、newへのポインタを返しますdouble
デビッドシュワルツ2013年

回答:


89

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

最初の例では:

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

ポインタは式の結果ですnewが、2番目の例では次のようになります。

unique_ptr<double> uptr2 (pd);

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

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

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

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

これが、可能であれば、一意のポインターを作成するための最初の形式が優れている理由です。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は、一意の所有権をモデル化するスマートポインターです。つまり、プログラム内の任意の時点で、指定されたオブジェクトへの(所有)ポインターは1つだけunique_ptrです。そのため、コピーできません。

準拠する必要のある暗黙のコントラクトを破らない方法でスマートポインターを使用する限り、メモリがリークされないことが保証され、オブジェクトの適切な所有権ポリシーが適用されます。生のポインタはこの保証を与えません。


3
こんにちは、コード内の、についてmodel object ownershipは何も理解できませんでした。これらの概念を学ぶためのトピック/リソースを提案していただけますか?integer leakenforcing ownership policy for object
udunの炎

1
私が使用できないunique_ptrエラーを取得せずに、: The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.、私が持っているにもかかわらず、#include <utility>#include <memory>。何かアドバイス?
匿名

15

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;

ここでは、を使用してheapIntを削除する必要があります。削除しないと、メモリリークが発生します。

このようなメモリリークを回避するために、unique_ptrが使用されます。unique_ptrは、スコープ外になると、heapIntが占有するスペースを自動的に削除します。したがって、unique_ptrを削除したり解放したりする必要はありません。


10

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

この場合:

unique_ptr<double> uptr2 (pd);

pduptr2スコープ外になると破壊されます。これにより、自動削除によるメモリ管理が容易になります。

ここでunique_ptr<int> uptr (new int(3));生のポインタがどの変数にも割り当てられていないことを除いて、の場合も同じです。


-1

cppreferenceから、std::unique_ptrコンストラクターの1つは

明示的なunique_ptr(ポインタp)noexcept;

したがって、新しいものを作成することstd::unique_ptrは、そのコンストラクターへのポインターを渡すことです。

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

またはそれはと同じです

int *int_ptr = new int(3);
std::unique_ptr<int> uptr (int_ptr);

違いは、使用後にクリーンアップする必要がないことです。std::unique_ptr(スマートポインタ)を使用しない場合は、このように削除する必要があります

delete int_ptr;

不要になったとき、またはメモリリークが発生したとき。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.