導入: なぜ shared_ptr で配列を扱うのか
C++におけるメモリ管理の基本はスマートポインタですが、かつて std::shared_ptr は単一オブジェクトを指すことしか考慮されていませんでした。そのため、配列を扱うには std::unique_ptr を使うか、std::vector を使うのが定石でした。しかし、所有権を共有しつつ動的配列を扱いたいケースでは、独自にデリータ(deleter)を指定する必要があり、コードが冗長になるという課題がありました。C++17からは std::shared_ptr が配列型をネイティブにサポートしたことで、この問題がスマートに解決されました。
基礎知識: スマートポインタとデリータの仕組み
std::shared_ptr は、内部で参照カウントを持ち、カウントがゼロになった時に保持しているポインタを delete する仕組みです。従来の std::shared_ptr
実装/解決策: std::shared_ptr の利用
実装は非常にシンプルです。テンプレート引数に配列型 T[] を指定し、new T[] で確保したメモリを渡すだけです。また、これまでの std::shared_ptr と異なり、配列インデックス演算子(operator[])がオーバーロードされているため、ポインタ演算を意識せず、通常の配列のように要素へアクセス可能です。
サンプルプログラム
以下のコードは、C++17以降の環境でコンパイル可能です。
include
include
int main() {
// C++17以降: 配列を管理する shared_ptr の生成
// コンストラクタで new int[5] を指定するだけで、
// 参照カウントが0になった際に自動的に delete[] が呼ばれます。
std::shared_ptr
// 配列インデックス演算子 [] が使用可能
for (int i = 0; i < 5; ++i) {
std::cout << "Index " << i << ": " << arr[i] << std::endl;
}
// 別の shared_ptr にコピーしても所有権は共有される
std::shared_ptr
std::cout << "共有後の値: " << sharedArr[2] << std::endl; return 0; // ここで参照カウントが0になり、自動的に delete[] が実行される }
応用・注意点: 実務での使い分け
注意点1: メモリ確保の方法
上記のサンプルでは new を直接使用していますが、C++20以降であれば std::make_shared
注意点2: コンテナとの比較
機能的には std::vector

コメント