【C++学習|実務向け】スマートポインタのget()を正しく使いこなす:生ポインタを取り出す際の注意点

導入

C++のスマートポインタ(std::unique_ptrやstd::shared_ptr)は、メモリ管理を自動化し、メモリリークを防ぐための強力なツールです。しかし、既存のC言語ライブラリとの連携や、特定の関数インターフェースに生ポインタ(raw pointer)を渡す必要がある場面では、スマートポインタから生ポインタを取り出す必要があります。ここで使用するのがメンバ関数のget()ですが、これを誤用するとメモリ破損や二重解放(double free)の原因となります。本記事では、安全なget()の運用方法を解説します。

基礎知識

スマートポインタは、所有権を管理するためのラッパーオブジェクトです。std::getは主にstd::tupleから要素を取り出す際に使用されますが、スマートポインタに対しては使用できません。スマートポインタから内部で保持している生ポインタを取得するには、メンバ関数として定義されているget()を呼び出します。
重要な点は、get()は所有権を移動したり共有したりしないという点です。あくまで「現在保持しているポインタの値を覗き見る」ための関数であり、取得した生ポインタに対してdeleteを実行してはいけません。

実装/解決策

スマートポインタのget()を利用する際は、以下の原則を守ってください。
1. 取得した生ポインタを、スマートポインタの生存期間を超えて保持しない。
2. 取得した生ポインタに対してdeleteを呼ばない。
3. 可能な限り、関数引数にはスマートポインタを渡さず、生の参照(T&)や生ポインタ(T)を渡す設計にする。

サンプルプログラム

以下のコードは、スマートポインタから生ポインタを取り出し、外部関数へ渡す際の推奨されるパターンです。

include
include

// 生ポインタを受け取る既存のライブラリ関数を想定
void processRawPointer(int ptr) {
if (ptr) {
std::cout << "値: " << ptr << std::endl; } } int main() { // スマートポインタの作成 std::unique_ptr uptr = std::make_unique(42);

// 1. メンバ関数 get() を使って生ポインタを取得
int rawPtr = uptr.get();

// 2. 外部関数へ渡す(所有権は渡さないため安全)
processRawPointer(rawPtr);

// 3. 注意:ここで delete rawPtr; をしてはいけません!
// スマートポインタがスコープを抜ける際に自動的に解放されます

return 0;
}

応用・注意点

現場で陥りやすいバグとして、get()で取得したポインタを別のスマートポインタでラップして管理しようとするケースがあります。

危険な例:
std::unique_ptr p1 = std::make_unique(10);
std::shared_ptr p2(p1.get()); // 間違い!

上記のように行うと、p1とp2の両方が同じメモリ領域を「自分が所有している」と判断し、それぞれの寿命が尽きたタイミングで二重解放(double free)が発生し、プログラムがクラッシュします。
スマートポインタから別の所有権管理へ移行したい場合は、std::unique_ptrならstd::moveを、std::shared_ptrならコピーコンストラクタを使用してください。get()はあくまで「一時的な参照」を得るためのものであると認識しておくことが、堅牢なコードを書くための近道です。

コメント

タイトルとURLをコピーしました