C++レビュー|goto禁止と例外処理理由明示レビュー技術
この記事のポイント
- goto文をレビューで摘出する力を養う
- 例外処理の理由説明が設計品質を左右する理由を理解する
- レビューアーが制御構造と保守性を読む技術を身につける
C++は柔軟な制御構造を許しますが、
柔軟さゆえに設計崩壊を呼びやすいポイント も存在します。
goto文と例外理由の明示はその代表例です。
1. なぜgoto禁止と例外コメントが重要なのか?
1-1. goto使用が危険な理由
- 制御構造が分岐と合流でねじれやすくなる
- 後から読んでも意図が追いにくい
- エラーハンドリングで乱用されやすい
1-2. 例外理由を明示すべき理由
- 何を違反した結果の例外なのかが読めなくなる
- 契約違反なのか環境依存なのか保守者が迷う
- 例外文脈が曖昧になるとデバッグが困難化する
1-3. レビューアーは以下を確認する
チェック項目 |
---|
gotoを使っていないか |
gotoが本当に必要な場面か(通常必要ない) |
throwの直前に理由説明があるか |
例外種別(契約違反・実行時エラー)が整理されているか |
2. 良い実装例:goto不使用・例外理由明示
#include <string>
#include <stdexcept>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
int responseCode;
std::string requestedAt;
};
class ApiRequestProcessor {
public:
void process(const ApiRequestLog& log) {
validate(log);
executeRequest(log);
logProcessing(log);
}
private:
void validate(const ApiRequestLog& log) {
if (log.endpoint.empty()) {
// エンドポイント未指定は契約違反
throw std::invalid_argument("APIエンドポイントが指定されていません");
}
if (log.responseCode < 100 || log.responseCode > 599) {
// HTTPレスポンスコード範囲外は契約違反
throw std::invalid_argument("HTTPレスポンスコードが不正です");
}
}
void executeRequest(const ApiRequestLog& log) {
// リクエスト処理
}
void logProcessing(const ApiRequestLog& log) {
// ログ記録処理
}
};
- 制御フローは通常の構造で整理
- 例外は契約違反に限定し、理由を明記
- 保守時の理解コストを下げている
3. 良くない実装例:goto使用+例外理由不足
#include <string>
#include <stdexcept>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
int responseCode;
std::string requestedAt;
};
class ApiRequestProcessor {
public:
void process(const ApiRequestLog& log) {
if (log.endpoint.empty()) {
goto error;
@Reviewergotoは使用しないでください。制御構造の流れが読みにくくなります。 }
if (log.responseCode < 100 || log.responseCode > 599) {
goto error;
}
executeRequest(log);
logProcessing(log);
return;
error:
throw std::invalid_argument("invalid input");
@Reviewer例外の理由説明が不足しています。契約違反の内容をコメントしてください。@Reviewer例外メッセージが曖昧です。invalidの具体的理由を書いてください。 }
private:
void executeRequest(const ApiRequestLog& log) {
// リクエスト処理
}
void logProcessing(const ApiRequestLog& log) {
// ログ記録処理
}
};
改善例
#include <string>
#include <stdexcept>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
int responseCode;
std::string requestedAt;
};
class ApiRequestProcessor {
public:
void process(const ApiRequestLog& log) {
validate(log);
executeRequest(log);
logProcessing(log);
}
private:
void validate(const ApiRequestLog& log) {
if (log.endpoint.empty()) {
// 契約違反: エンドポイント未指定
throw std::invalid_argument("APIエンドポイント未指定");
}
if (log.responseCode < 100 || log.responseCode > 599) {
// 契約違反: レスポンスコード異常
throw std::invalid_argument("HTTPレスポンスコード不正");
}
}
void executeRequest(const ApiRequestLog& log) { }
void logProcessing(const ApiRequestLog& log) { }
};
- 制御構造が整理され、例外理由も明確化
- 保守・障害調査時に役立つ設計意図が残る
4. ケース別レビュー:goto誤用パターン
リソース開放管理でgotoに逃げる例
bool ApiRequestInitializer::initialize() {
if (!loadConfig()) {
goto error;
}
if (!connectDatabase()) {
goto cleanupConfig;
}
if (!registerHandlers()) {
goto cleanupDatabase;
}
@Reviewergotoでリソース解放順を管理しないでください。RAII利用でスコープ自動解放を検討しましょう return true;
cleanupDatabase:
disconnectDatabase();
cleanupConfig:
unloadConfig();
error:
return false;
}。
改善例:RAII適用
RAIIを使って解放処理を自動化することで、gotoを使わないようにします。
RAIIとは
class ConfigGuard {
public:
ConfigGuard() : loaded(false) {}
~ConfigGuard() { if (loaded) unloadConfig(); }
bool load() { loaded = loadConfig(); return loaded; }
private:
bool loaded;
};
class DatabaseGuard {
public:
DatabaseGuard() : connected(false) {}
~DatabaseGuard() { if (connected) disconnectDatabase(); }
bool connect() { connected = connectDatabase(); return connected; }
private:
bool connected;
};
bool ApiRequestInitializer::initialize() {
ConfigGuard config;
if (!config.load()) return false;
DatabaseGuard db;
if (!db.connect()) return false;
if (!registerHandlers()) return false;
return true;
}
- goto不要
- スコープで自然に解放
- 例外安全性も上がる
5. チェックリストまとめ
観点 | 確認内容 |
---|---|
goto排除 | 使用されていないか |
制御構造 | 本来なら通常フローで表現可能ではないか |
例外理由説明 | throw直前に説明があるか |
例外分類整理 | 契約違反と実行時例外を整理しているか |
例外メッセージ | 汎用的すぎないか |
リソース解放設計 | RAIIで管理されているか |
例外安全性 | 途中例外でも後処理が漏れていないか |
6. まとめ
goto禁止+例外理由明示レビューは、設計品質と保守性の基盤を守る重要観点です。
レビューアーは
- 制御構造のねじれを摘出
- 例外の文脈と理由を読み取る
- 契約違反 vs 実行時異常を区別
- RAII設計適用を促す
こうした読み取りが自然にできると、
設計レビューの質が一段高まります。