「C++の基礎 - スマートポインタ(unique ptr)」の版間の差分

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

Wiki がページ「C++の基礎 - スマートポインタの使い方(unique ptr)」を「C++の基礎 - スマートポインタ(unique ptr)」に、リダイレクトを残さずに移動しました
編集の要約なし
22行目: 22行目:
・deleter(後述)を指定することができる。<br>
・deleter(後述)を指定することができる。<br>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  #include<iostream>
  #include<iostream>
  #include<memory>    // スマートポインタを使用する時に指定する
  #include<memory>    // スマートポインタを使用する時に指定する
59行目: 59行目:
   return 0;
   return 0;
  }
  }
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


66行目: 66行目:
尚、使用の際には#include <memory>を指定する必要がある。<br>
尚、使用の際には#include <memory>を指定する必要がある。<br>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // まず、unique_ptr<T>にメモリの所有権を委ねるには、コンストラクタで指定するかreset(pointer)を使う。
  // まず、unique_ptr<T>にメモリの所有権を委ねるには、コンストラクタで指定するかreset(pointer)を使う。
  // C++14以降では、make_unique<T>関数を使って作成することができる。
  // C++14以降では、make_unique<T>関数を使って作成することができる。
96行目: 96行目:
  std::unique_ptr<int> ptr4;
  std::unique_ptr<int> ptr4;
  ptr4 = std::move(ptr3);                  // ptr4の所有権がptr5に移動する
  ptr4 = std::move(ptr3);                  // ptr4の所有権がptr5に移動する
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // メモリの解放は、ディストラクタや reset(pointer)を使う。
  // メモリの解放は、ディストラクタや reset(pointer)を使う。
   
   
104行目: 104行目:
  std::unique_ptr<int> ptr(new int(10));
  std::unique_ptr<int> ptr(new int(10));
  ptr.reset();
  ptr.reset();
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // 生のポインタが欲しい時は、get()かrelease()を使う
  // 生のポインタが欲しい時は、get()かrelease()を使う
   
   
116行目: 116行目:
  pint = ptr.release();
  pint = ptr.release();
  delete pint;
  delete pint;
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // unique_ptr<T[]>のように指定すれば、配列を扱うこともできる
  // unique_ptr<T[]>のように指定すれば、配列を扱うこともできる
  // 配列型の場合、operator[](size_t)を使用することができる
  // 配列型の場合、operator[](size_t)を使用することができる
127行目: 127行目:
     ptrArray[i] = i;
     ptrArray[i] = i;
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
  <source lang="c++">
  <syntaxhighlight lang="c++">
  // ポインタの保持するメモリにアクセスするには、通常のポインタ同様に、operator*()やoperator->()が使用できる
  // ポインタの保持するメモリにアクセスするには、通常のポインタ同様に、operator*()やoperator->()が使用できる
  std::unique_ptr<std::string> pStr(new std::string("test"));
  std::unique_ptr<std::string> pStr(new std::string("test"));
138行目: 138行目:
  // operator->()で、string型のsize関数を呼び出せる
  // operator->()で、string型のsize関数を呼び出せる
  unsigned int StrSize = pStr->size();   
  unsigned int StrSize = pStr->size();   
  </source>
  </syntaxhighlight>
<br><br>
 
== スマートポインタの使いどころ ==
==== 関数の引数 ====
関数を通して所有権を渡す時は、<code>std::unique_ptr</code>または<code>std::shared_ptr</code>を使用する。<br>
<code>std::unique_ptr</code>は完全に所有権を譲渡、<code>std::shared_ptr</code>は共有する。<br>
それ以外は、生ポインタ(または参照)を使用する。<br>
<br>
==== 関数の戻り値 ====
ファクトリ関数(オブジェクトを生成する関数)の戻り値は、原則、<code>std::unique_ptr</code>を使用する。<br>
<br>
<code>std::shared_ptr</code>で扱いたい場合、受け取った<code>std::unique_ptr</code>を<code>std::shared_ptr</code>に代入するとよい。<br>
(<code>std::shared_ptr</code>のコンストラクタにおいて、<code>std::unique_ptr&&</code>を取るものが存在する)<br>
<br>
<syntaxhighlight lang="c++">
// factory methodで作成したオブジェクト
std::unique_ptr<Foo> CreateFoo();
// std::unique_ptrをstd::shared_ptrに代入する
std::shared_ptr<foo> sp = CreateFoo();
</syntaxhighlight>
<br>
オブジェクト内のメンバへのポインタを返す場合等は、生ポインタまたは参照でよい。<br>
変更が不要な場合、constキーワードを付加すること。<br>
また、オブジェクトの生存期間には注意が必要である。<br>
<syntaxhighlight lang="c++">
class Foo
{
    private:
      Bar bar;
    public:
      const Bar& GetBar() const { return bar; }
};
</syntaxhighlight>
<br>
==== クラスのメンバ変数 ====
所有権を持っている場合、<code>std::unique_ptr</code>または<code>std::shared_ptr</code>を使用する。<br>
所有権を持っていない場合、生ポインタまたは参照を使用する。<br>
この時、参照しているオブジェクトの生存期間に注意が必要である。<br>
<br>
生存期間の制御が難しい場合、<code>std::weak_ptr</code>を使用することもある。<br>
<br>
<code>std::shared_ptr</code>と<code>std::weak_ptr</code>は必要な場合のみ使用する。<br>
<code>std::shared_ptr</code>を使用することで、オブジェクトの生存期間の制御が難しくなる。<br>
<br>
同様に、<code>std::weak_ptr</code>も無闇に使用しない。<br>
複数の場所で使用されるオブジェクトの生存期間を制御することが難しい場合や、循環参照の解決には便利である。<br>
また、<u>所有権を持たないオブジェクトへの参照は全て<code>std::weak_ptr</code>にする</u>、といったことは行わないこと。<br>
<br>
==== スマートポインタのコスト ====
<code>std::unique_ptr</code>は、オーバーヘッドはほぼ無い。<br>
メモリ使用量、コードサイズ、実行速度の全てにおいて、生ポインタを<code>new</code>および<code>delete</code>する場合に負けることはない。<br>
<br>
<code>std::shared_ptr</code>および<code>std::weak_ptr</code>は、オーバーヘッドがある。<br>
コントロールブロックと呼ばれる別のメモリ領域がヒープから取られることで、格納するオブジェクトと合わせて2回のメモリ確保が行われる。<br>
また、コピー時には、リファレンスカウントの操作が行われる。<br>
これは、オブジェクトの生成・破棄に比べれば遥かに軽い操作であるが、スレッドセーフにするために排他されていたりもするので0ではない。<br>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]