C++レビュー|shared_from_thisの安全利用設計と責務整理レビュー観点
この記事のポイント
- shared_from_thisの安全利用設計をレビューアーが読み解く技術を整理
- 所有権保証前提の責務設計と事故防止設計をレビュー観点として体系化
- shared_ptrとの連携設計におけるレビュー判断力を養う
そもそもshared_from_thisとは
C++におけるshared_from_thisは
「自身のshared_ptrを動的に取得できる仕組み」
です。クラス定義にstd::enable_shared_from_thisを継承することで利用可能になります。
struct ApiRequestLog : std::enable_shared_from_this<ApiRequestLog> {
std::shared_ptr<ApiRequestLog> getSelf() {
return shared_from_this();
}
};shared_from_thisを使う目的
- コールバック登録に自身を登録
- 非同期処理で自身の寿命保証
- observer通知時の寿命延長
レビューアーは
「このshared_from_this利用は寿命安全を保証しているか?」
を読み解く役割を持ちます。
なぜこれをレビューするのか
shared_from_thisは便利ですが、以下の事故を誘発します。
- 所有権未構築状態での呼び出し(クラッシュ)
- 部分寿命保証崩壊(コールバック登録遅延中の破棄)
- 責務分離崩壊(所有権管理が分散)
レビュー段階で
「shared_ptr起点で安全に統治できる設計になっているか」
を読み取る能力が重要です。
レビューアー視点
- 必ずshared_ptr管理下でshared_from_thisを呼んでいるか
- 所有権未構築経路でshared_from_thisが呼ばれ得ないか
- shared_from_thisの責務乱用(所有権分散)になっていないか
- observer・非同期処理の寿命保証用途に限定されているか
- API契約上shared_ptr構築責務が開発チーム全体で統一されているか
開発者視点
- インスタンス生成時点でshared_ptr経由構築を必須とする
- shared_from_thisは寿命延長時専用に利用
- 非shared_ptr所有経路を禁止する設計統一
- shared_from_this利用箇所は極力限定
良い実装例
想定:非同期処理における寿命延長用途
良い設計例
#include <memory>
#include <thread>
#include <iostream>
struct ApiRequestLog : std::enable_shared_from_this<ApiRequestLog> {
int requestId;
void processAsync() {
auto self = shared_from_this();
std::thread([self] {
std::cout << self->requestId << std::endl;
}).detach();
}
};
void process() {
auto log = std::make_shared<ApiRequestLog>();
log->requestId = 123;
log->processAsync();
}良いポイント
- shared_ptr構築必須経路のみでshared_from_this使用
- 非同期処理中も寿命保証
- shared_ptr管理下のみで生存
レビュー観点
- shared_from_this使用前にshared_ptr管理下であることが構造保証されているか
- observer・非同期寿命延長用途に限定されているか
- shared_ptr所有構築経路が全チームで統一されているか
- shared_from_this経由で所有権転送設計が行われていないか
- enable_shared_from_this継承が妥当範囲に限定されているか
良くない実装例: ケース1(所有権未構築経路)
問題例①
void unsafe() {
ApiRequestLog log;
log.shared_from_this()->processAsync();
}
@Reviewershared_ptr管理下でないオブジェクトはshared_from_this使用禁止です。shared_ptr経由の構築経路に統一してください。
改善例
改善例①
auto log = std::make_shared<ApiRequestLog>();
log->processAsync();良くない実装例: ケース2(所有権分散化利用)
問題例②
class Manager {
public:
void save(ApiRequestLog* logEntry) {
auto shared = logEntry->shared_from_this();
logs_.push_back(shared);
}
private:
std::vector<std::shared_ptr<ApiRequestLog>> logs_;
};
@Reviewer生ポインタ経由でshared_from_this使用は寿命保証不備を誘発します。API契約ごとshared_ptr受領に統一してください。
改善例
改善例②
void save(std::shared_ptr<ApiRequestLog> logEntry) {
logs_.push_back(logEntry);
}良くない実装例: ケース3(共有所有経路混在)
問題例③
void mixed() {
ApiRequestLog rawLog;
auto shared1 = rawLog.shared_from_this();
auto shared2 = std::make_shared<ApiRequestLog>();
}
@Reviewershared_ptr未管理オブジェクトと混在利用は寿命崩壊を招きます。new禁止、shared_ptr統一構築に整理してください。
改善例
改善例③
auto shared = std::make_shared<ApiRequestLog>();観点チェックリスト
まとめ
shared_from_thisレビューは
「所有権統一統治構造の中で安全に寿命延長のみ活用されているか確認するレビュー」です。
レビューアーは常に
- shared_ptr構築統一が守られているか?
- 生ポインタ経由の事故経路が存在しないか?
- shared_from_thisは非同期・通知延長用途に限定されているか?
を静的に読み解き、事故経路遮断設計へ誘導します。
