導入
C++での開発において、std::unique_ptrやstd::shared_ptrはリソース管理を強力にサポートしてくれます。しかし、すべての関数引数にスマートポインタを渡していませんか?実は、関数内で「一時的に対象を利用するだけ」の場合、スマートポインタを渡すのは設計上のミスになり得ます。本記事では、所有権を移動させずに安全にオブジェクトを参照する「オブザーバ(観測者)」パターンについて解説します。
基礎知識
C++における所有権(Ownership)とは、リソースの寿命を管理する責任のことです。
std::unique_ptrを引数に渡すと、関数側がそのオブジェクトの所有権を奪う(あるいは共有する)可能性を示唆します。しかし、呼び出し元のオブジェクトがそのまま存在し続けるはずなのに、わざわざスマートポインタを渡す必要はありません。
ここで登場するのが「生のポインタ(T)」や「参照(T&)」です。これらは「所有権を持たずに一時的にアクセスする」という意図を明確にするためのツールです。
実装/解決策
関数が「所有権を要求しない」ことを示すには、以下の方針を徹底します。
1. 基本的に、所有権を移動しない場合は参照(T&)を渡す。
2. オブジェクトがnullである可能性がある場合は生のポインタ(T)を渡す。
これらを使うことで、関数呼び出し側は「この関数は私の所有物を勝手に解放したりしない」と確信を持ってコードを書くことができます。
サンプルプログラム
以下のコードは、スマートポインタを所有するクラスから、一時的な処理を行う関数へアクセスを許可する例です。
include
include
include
// リソースを管理するクラス
class Resource {
public:
void sayHello() { std::cout << "こんにちは!" << std::endl; }
};
// 観測のみを行う関数
// 参照を受け取ることで「この関数は所有権に関与しない」ことを明示
void use_object(Resource& res) {
res.sayHello();
}
int main() {
// 所有権はmain関数にある
auto myResource = std::make_unique
// 所有権を渡さず、一時的に参照を渡す
use_object(myResource);
return 0;
}
応用・注意点
現場で陥りやすいのが「とりあえずstd::shared_ptrを渡しておけば安全だろう」という考え方です。しかし、不要な共有は参照カウントの更新コストを発生させ、パフォーマンスを低下させます。
また、生のポインタを渡す際は「そのポインタが指す先の寿命が、関数実行中ずっと保証されていること」が前提です。非同期処理などでオブジェクトが破棄される可能性がある場合は、std::weak_ptrを活用してロックを行うなど、状況に応じた使い分けを心がけましょう。所有権を「持たせる」のか「借りるだけ」なのか。この区別こそが、堅牢なC++プログラムを作る第一歩です。

コメント