cpp-common-code/readme/cpp-coding-conv.md

337 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# C++ コーディング規約
## 1. 一般的なガイドライン
1. **モダン C++C++17 以上)** を前提とする。
2. 生ポインタより、まず **`std::unique_ptr` / `std::shared_ptr` / `std::vector` など RAII** を優先する。
3. 例外を使う場合は、**例外 or エラーコードのどちらかに統一**する。
4. `new` / `delete` は基本的に直接使わず、スマートポインタやコンテナを使う。
5. ヘッダ/ソース分割は `*.h` / `*.cpp`(または `*.hpp` / `*.cpp`)で行う。
6. 自動整形には **`clang-format`** を利用する。
---
## 2. コメント/ドキュメント
### 2.1 ファイルコメント
```cpp
// user_service.h - ユーザー関連のユースケースを提供するクラス群
#pragma once
// ...
```
### 2.2 クラスコメントDoxygen 推奨)
```cpp
/**
* @brief ユーザーを管理するサービスクラス。
*
* ユーザーの作成、取得、削除などの機能を提供する。
*/
class UserService {
public:
/// コンストラクタ
explicit UserService(UserRepository& repo);
/// ユーザーを作成する
User createUser(const std::string& name, int age);
private:
UserRepository& repo_;
};
```
### 2.3 メソッドコメント
```cpp
/**
* @brief ユーザーをIDで取得する。
*
* @throws std::runtime_error ユーザーが存在しない場合。
*/
User UserService::getUserById(int id);
```
---
## 3. 命名規則
1. **クラス名/構造体名**: `CamelCase`
```cpp
class UserService;
struct HttpRequest;
```
2. **メソッド・関数名**: `camelCase` または `snake_case`(プロジェクト内で統一)
```cpp
void addUser(const User& user);
int find_user(const std::string& name); // プロジェクト方針次第
```
3. **メンバ変数**:
* プレフィックスやサフィックスを付けるスタイルが多い
例: `snake_case_` / `m_name` / `_name` など
```cpp
class User {
public:
explicit User(std::string name, int age)
: name_(std::move(name)), age_(age) {}
private:
std::string name_;
int age_;
};
```
4. **定数**:
* グローバル定数には `k` プレフィックスを使う場合も多い。
```cpp
constexpr int kMaxUserCount = 1000;
```
5. **名前空間**: すべて小文字でプロジェクト名などを使う。
```cpp
namespace myapp::user {
// ...
}
```
---
## 4. インクルードガイドライン
1. ヘッダでのインクルードは **最小限** にする。前方宣言で済むなら前方宣言を使う。
```cpp
// user_service.h
#pragma once
#include <string>
namespace myapp {
class UserRepository; // 前方宣言
class UserService {
public:
explicit UserService(UserRepository& repo);
// ...
private:
UserRepository& repo_;
};
} // namespace myapp
```
2. ソースファイルでは対応するヘッダをまずインクルードし、その後に標準/外部ライブラリ。
```cpp
// user_service.cpp
#include "user_service.h"
#include "user_repository.h"
#include <stdexcept>
```
3. インクルード順は以下を推奨:
1. 自分のヘッダ
2. 同じモジュールのヘッダ
3. 標準ライブラリ
4. サードパーティヘッダ
---
## 5. エラーハンドリング
### 5.1 例外を使う場合
1. ロジック上の失敗には `throw` で例外を投げ、呼び出し側で `try`/`catch`。
```cpp
User UserService::getUserById(int id)
{
auto user = repo_.findById(id);
if (!user) {
throw std::runtime_error("User not found");
}
return *user;
}
```
2. 例外の種類は、`std::runtime_error` / `std::invalid_argument` などを使い分ける。
3. ライブラリ側では「例外を投げる API」と「エラーコードを返す API」を明確に分ける。
### 5.2 例外を使わない場合
1. 戻り値に `std::optional<T>` や `expected` パターン(独自実装)を使う。
```cpp
std::optional<User> UserService::tryGetUserById(int id)
{
return repo_.findById(id);
}
```
---
## 6. 複数ファイル間の分割(ヘッダ / ソース)
### 6.1 例: User と UserService
```text
include/
user.h
user_service.h
src/
user.cpp
user_service.cpp
main.cpp
```
#### `user.h`
```cpp
#pragma once
#include <string>
namespace myapp {
class User {
public:
User(int id, std::string name);
int id() const;
const std::string& name() const;
private:
int id_;
std::string name_;
};
} // namespace myapp
```
#### `user.cpp`
```cpp
#include "user.h"
namespace myapp {
User::User(int id, std::string name)
: id_(id), name_(std::move(name))
{
}
int User::id() const
{
return id_;
}
const std::string& User::name() const
{
return name_;
}
} // namespace myapp
```
#### `user_service.h`
```cpp
#pragma once
#include <memory>
#include "user.h"
namespace myapp {
class UserRepository;
class UserService {
public:
explicit UserService(UserRepository& repo);
User createUser(const std::string& name, int age);
private:
UserRepository& repo_;
};
} // namespace myapp
```
#### `user_service.cpp`
```cpp
#include "user_service.h"
#include "user_repository.h"
namespace myapp {
UserService::UserService(UserRepository& repo)
: repo_(repo)
{
}
User UserService::createUser(const std::string& name, int age)
{
// 仮実装: ID採番して保存するなど
int newId = repo_.nextId();
User user(newId, name);
repo_.save(user);
return user;
}
} // namespace myapp
```
---
## 7. clang-format / clang-tidy / VSCode 設定
### 7.1 `.clang-format`C と共有してもOK
```yaml
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
ColumnLimit: 100
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
NamespaceIndentation: All
```
### 7.2 VSCode 設定例
```json
{
"[cpp]": {
"editor.defaultFormatter": "ms-vscode.cpptools",
"editor.formatOnSave": true
},
"C_Cpp.clang_format_style": "file",
// clang-tidy を使う場合
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true
}
```