導入
C++11以降、メモリ管理には std::unique_ptr を利用するのが定石です。しかし、既存のC言語ライブラリを呼び出す場合や、所有権を関数の外部へ引き継ぐ必要がある場面では、std::unique_ptr が管理しているリソースを「生のポインタ(Rawポインタ)」として取り出す必要が出てきます。この記事では、所有権を適切に移行するための手法を解説します。
基礎知識
std::unique_ptr は、スコープを抜ける際に自動的に delete を実行する「所有権」を持つスマートポインタです。これに対して、Rawポインタはリソースの場所を示す単なるアドレスです。std::unique_ptr から Rawポインタを取り出す際に重要なのは、単にアドレスを参照するだけなのか、それとも「管理の責任(解放の義務)」を放棄するのかを明確に区別することです。
実装/解決策
所有権を完全に手放し、Rawポインタとして管理を引き継ぐためには release() メンバ関数を使用します。
release() を呼び出すと、std::unique_ptr は保持していたポインタを nullptr にリセットし、これまで持っていた管理権限(破棄の責任)を呼び出し側に譲渡します。これにより、スコープを抜けてもスマートポインタによる自動的な delete は発生しなくなります。
サンプルプログラム
以下のコードは、std::unique_ptr から Rawポインタへ所有権を移譲する基本的な実装例です。
include <iostream>
include <memory>
class MyResource {
public:
MyResource() { std::cout << "リソース生成" << std::endl; }
~MyResource() { std::cout << "リソース破棄" << std::endl; }
void sayHello() { std::cout << "こんにちは!" << std::endl; }
};
int main() {
// 1. スマートポインタで管理を開始
std::unique_ptr<MyResource> smartPtr = std::make_unique<MyResource>();
// 2. release() を呼び出し、所有権を放棄してRawポインタを取得
// これ以降、smartPtr は nullptr になり、自動削除は行われません
MyResource rawPtr = smartPtr.release();
if (smartPtr == nullptr) {
std::cout << "スマートポインタは所有権を手放しました" << std::endl;
}
// 3. 取得したRawポインタを操作
rawPtr->sayHello();
// 4. 所有権を引き継いだので、最後に手動で削除する必要がある
delete rawPtr;
return 0;
}
応用・注意点
注意が必要なポイント
・メモリリークの危険性: release() を呼んだ瞬間から、そのメモリの管理は開発者の手元に戻ります。もし delete を忘れると、メモリリークの原因となります。
・get() との混同: 単にポインタのアドレスだけを参照したい(所有権は手放したくない)場合は、get() を使用してください。get() は所有権を保持したまま Rawポインタを返すため、誤って delete を呼び出すと二重解放(Double Free)でクラッシュします。
・設計の再検討: release() を多用しなければならない状況は、所有権の設計が複雑になっているサインかもしれません。可能な限りスマートポインタのまま受け渡す設計を優先しましょう。

コメント