次の関数はコンパイルされません。
std::unique_ptr<int> foo()
{
int* answer = new int(42);
return answer;
}
std::unique_ptr<int> bar()
{
return new int(42);
}
これは少し不便だと思います。std::unique_ptr<T>(T*)
明示的にする理由は何でしたか?
次の関数はコンパイルされません。
std::unique_ptr<int> foo()
{
int* answer = new int(42);
return answer;
}
std::unique_ptr<int> bar()
{
return new int(42);
}
これは少し不便だと思います。std::unique_ptr<T>(T*)
明示的にする理由は何でしたか?
マネージドポインターが生のポインターの所有権を暗黙的に取得することは望ましくありません。これは、未定義の動作になる可能性があるためです。関数void f( int * );
と呼び出しについて考えてみましょうint * p = new int(5); f(p); delete p;
。f
ここで、誰かが(任意のタイプの)マネージポインターを取得するようにリファクタリングし、暗黙の変換が許可されたと想像してください。暗黙の変換が許可されvoid f( std::unique_ptr<int> p );
ている場合、コードはコンパイルされますが、未定義の動作が発生します。
int x = 5; f( &x );
同様に、ポインタが動的に割り当てられない可能性があることを考慮してください。
所有権の取得は、明示的にする方がよいほど重要な操作です。プログラマー(コンパイラーではなく)は、リソースをスマートポインターで管理する必要があるかどうかを認識しています。
短い答え:
明示的なコンストラクターは、危険なコードを書くことを困難にします。つまり、暗黙のコンストラクターは、危険なコードをより簡単に作成するのに役立ちます。
長い答え:
コンストラクターが暗黙的である場合、そのようなコードを簡単に書くことができます:
void f(std::unique_ptr<int> param)
{
//code
} //param will be destructed here, i.e when it goes out of scope
//the pointer which it manages will be destructed as well.
ここで危険な部分を見てください:
int *ptr = new int;
f(ptr);
//note that calling f is allowed if it is allowed:
//std::unique_ptr<int> test = new int;
//it is as if ptr is assigned to the parameter:
//std::unique_ptr<int> test = ptr;
//DANGER
*ptr = 10; //undefined behavior because ptr has been deleted by the unique_ptr!
コメントをお読みください。上記のコードスニペットの各部分について説明します。
生のポインターを使用して呼び出す場合f()
、プログラマーは、のパラメーター型がポインターの所有権を取得し、スコープ外になったときに所有権を取得することに気付かない場合がf()
ありstd::unique_ptr
ますdelete
。一方、プログラマーはそれを使用する可能性があり、delete
それがすでに削除されていることに気付くことさえありません!これはすべて、rawポインタから。への暗黙std::unique_ptr
の変換が原因で発生します。
まったく同じ理由でコンストラクターがあることに注意しstd::shared_ptr
てください。explicit