Claude Code的「项目宪法」

Claude Code 是 Anthropic 推出的终端内 AI 编程助手,而 CLAUDE.md 文件就是它的项目级配置入口。你可以把它理解为一份「项目宪法」——所有 Claude Code 在项目内的回答、生成代码、重构建议,都会遵循这份文件里的规则。

对于 C++ 项目来说,最让开发者头疼的两件事往往是:标准版本不统一(有人偷偷用了 C++20 特性,但项目只支持 C++17)和内存管理风格混乱(裸指针和智能指针混用,所有权不清)。CLAUDE.md 恰好能一次性解决这两个问题。

1. CLAUDE.md 的基本用法

在项目根目录下创建 CLAUDE.md 文件,Claude Code 会在每次启动时自动加载。文件采用 Markdown 格式,内容可以是任何你希望 Claude 遵守的规则、风格指南或项目背景信息。

# CLAUDE.md 基本结构示例
项目背景
这是一个 C++ 游戏服务端项目,需要处理高并发网络请求。
编码规范
使用 C++17 标准
统一使用智能指针管理内存
命名风格遵循 Google C++ Style Guide

文件生效后,当你在项目中让 Claude Code 生成代码或重构时,它会自动遵循你设定的约束。不需要每次都手动提醒「请用 C++17」或「不要用裸指针」。

2. 锁定 C++ 标准版本

C++ 各版本之间的特性差异很大——C++14、C++17、C++20 甚至 C++23 都引入了大量新语法和库。如果你的项目 CI 环境只支持 C++17,但 AI 生成了一段包含 std::spanconcepts 的代码,后续排查会非常痛苦。

CLAUDE.md 中明确声明标准版本是最直接的解法:

## C++ 标准要求
- 本项目严格使用 C++17 标准,CMake 中已设置 `set(CMAKE_CXX_STANDARD 17)`
- 禁止使用 C++20/23 特性,包括但不限于:
  - Concepts(`requires`、`concept`)
  - Ranges(`std::ranges`)
  - `std::span`
  - 协程(`co_await`、`co_return`)
  - `std::format`(请使用 `fmtlib/fmt` 库替代)
  - 三路比较运算符(`<=>`)
- 可以使用 C++17 特性:
  - `if constexpr`
  - 结构化绑定(`auto [a, b] = ...`)
  - `std::optional`、`std::variant`、`std::string_view`
  - 折叠表达式

这种「白名单 + 黑名单」的方式,能让 AI 精确知道你项目的技术边界。如果你还处于从 C++14 升级到 C++17 的过渡期,也可以把规则写得更有针对性:

## 过渡期标准策略
- 核心模块使用 C++17,但需要保持对 C++14 编译器的兼容性
- 新代码中优先使用 C++17 特性,但需要提供 C++14 的降级路径
- `std::optional` 和 `std::variant` 暂时禁止,请使用 Boost 对应实现

3. 锁定内存管理规范

C++ 内存管理是 Bug 的重灾区。不同团队、不同模块之间的内存管理风格一旦不统一,代码审查成本会直线上升。借助 CLAUDE.md,你可以把团队的内存管理约定固化成 AI 必须遵守的规则。

3.1 智能指针优先策略

如果你的项目已经完全拥抱现代 C++,可以这样写:

## 内存管理规范
- 严格禁止使用裸指针管理资源所有权,以下情况除外:
  - 与 C 接口交互(必须封装在 RAII 包装内)
  - 作为函数参数传递非拥有指针(用 `T*` 表示「可选引用」,不转移所有权)
- `new` 和 `delete` 关键字禁止出现在业务代码中
- 优先使用工厂函数:
  - `std::make_unique<T>(...)` 创建独占所有权
  - `std::make_shared<T>(...)` 创建共享所有权
- 禁止使用 `std::auto_ptr`(C++17 中已被移除)

3.2 所有权语义明确化

内存问题的根源往往不是「用没用智能指针」,而是所有权不清晰。可以在 CLAUDE.md 中直接约定所有权传递规则:

## 所有权传递规范
- 函数如果接管对象所有权,参数使用 `std::unique_ptr<T>` 按值传递
- 函数如果只是临时使用对象,参数使用 `const T&` 或 `T*`
- 函数如果返回新创建的对象,必须返回 `std::unique_ptr<T>`
- 禁止返回裸指针指向堆上分配的新对象(极易导致内存泄漏)
- 使用 `std::weak_ptr` 打破 `std::shared_ptr` 循环引用

3.3 性能敏感场景的例外规则

如果你在做游戏引擎、高频交易或嵌入式开发,可能需要在某些模块中放宽规则:

## 内存管理例外
- 渲染管线、网络收发包缓冲区等热路径代码可以使用裸指针和自定义内存池
- 例外模块必须满足以下条件:
  - 在类注释中明确说明内存管理策略
  - 提供 RAII 守卫或作用域级别的自动回收机制
  - 通过 AddressSanitizer / Valgrind 验证无泄漏
- Claude Code 在生成例外模块代码时,必须同时生成对应的 RAII 包装

4. 进阶:组合约束与工具链锁定

单独的 C++ 标准和内存规范已经很实用了,但 CLAUDE.md 的强大之处在于,你可以把所有约束「组合」起来,形成完整的技术栈锁定。

4.1 编译器和平台锁定

## 编译与平台约束
- 编译器:GCC 11+ / Clang 14+ / MSVC 2022
- 目标平台:Linux x86_64(Ubuntu 22.04)、Windows 10+
- CMake 最低版本:3.20
- 开启编译选项:`-Wall -Wextra -Wpedantic -Werror`
- 使用 AddressSanitizer(`-fsanitize=address`)进行开发环境测试

4.2 第三方库白名单

## 依赖库规范
- 允许使用的第三方库:
  - Boost(仅限 asio、beast、json 模块)
  - fmtlib/fmt 10.x
  - Google Test 1.14+
  - spdlog 1.12+
- 禁止引入新的第三方库,除非经过技术评审
- 所有依赖通过 vcpkg / Conan 管理,禁止手动拷贝源码

4.3 代码审查检查清单

## Review 检查项
Claude 在生成代码后,请自查以下项目:
1. 是否使用了项目允许的 C++ 标准特性?
2. 是否存在裸 `new` / `delete`?
3. 所有权语义是否清晰(谁创建、谁销毁)?
4. 是否有潜在的循环引用(`shared_ptr` 互相持有)?
5. 是否引入了未批准的第三方依赖?

5. 完整 CLAUDE.md 配置示例

下面是一份可以直接用在 C++ 项目中的完整配置,你可以根据团队实际情况裁剪:

# CLAUDE.md — C++ Project Constitution
项目简介
本项目是一个高性能 C++ 网络服务框架,服务于公司核心业务。
C++ 标准
核心标准:C++17
禁止使用 C++20/23 特性(Concepts、Ranges、Coroutines、std::span、三路比较)
允许的 C++17 特性:if constexpr、结构化绑定、std::optional、std::variant、std::string_view、折叠表达式
内存管理
禁止使用裸 new / delete(与 C 接口交互除外)
统一使用 std::make_unique / std::make_shared 创建堆对象
函数参数语义:
所有权转移 → std::unique_ptr&lt;T&gt; 按值
只读访问 → const T&amp; 或 const T*
可选修改 → T*(不转移所有权)
禁止返回指向堆对象的裸指针
用 std::weak_ptr 打破循环引用
编译与工具链
编译器:GCC 11+ / Clang 14+
CMake ≥ 3.20
编译选项:-Wall -Wextra -Wpedantic -Werror
开发环境启用 ASan
依赖管理
vcpkg 统一管理依赖
白名单:Boost(asio/beast)、fmtlib/fmt、Google Test、spdlog
禁止未经评审引入新依赖
代码风格
遵循 Google C++ Style Guide
命名规范:类名 PascalCase、函数名 snake_case、成员变量后置下划线 value_
头文件使用 #pragma once
禁止 using namespace 在头文件的全局作用域
审查自查
生成代码后自查:标准合规、内存安全、所有权清晰、无未授权依赖。

6. 实际效果:一个对比案例

如果没有 CLAUDE.md,当你对 Claude Code 说「写一个 TCP 连接管理器」,它可能会生成这样的代码:

// 没有规则的产物(不推荐)
class Connection {
    Socket* socket_;  // 裸指针,所有权不明确
public:
    explicit Connection(Socket* s) : socket_(s) {}
    ~Connection() { delete socket_; }  // 删除的是自己创建的吗?
};

有了 CLAUDE.md 约束后,同样的指令会生成:

// 受 CLAUDE.md 约束的产物(推荐)
class Connection {
    std::unique_ptr<Socket> socket_;  // 独占所有权,语义清晰
public:
    explicit Connection(std::unique_ptr<Socket> socket)
        : socket_(std::move(socket)) {}
    // 析构函数自动释放,无需手动 delete
};

后者不仅避免了手动 delete,还通过 unique_ptr 明确表达了「Connection 独占 Socket 所有权」的语义——这正是 CLAUDE.md 的核心价值:让 AI 产出的代码天然符合团队规范,而不是事后修补

7. 进阶技巧

7.1 分模块定规则

大型项目中,不同子模块可能有不同约束。你可以在子目录下放置独立的 CLAUDE.md

# src/legacy/CLAUDE.md
本目录为遗留代码,使用 C++14 标准,内存管理沿用裸指针 + 引用计数模式。
修改时请保持与现有代码风格一致,不要引入智能指针。

Claude Code 会自动加载当前工作目录下最近的 CLAUDE.md,子目录规则会覆盖根目录规则。

7.2 借助 Git Hook 自动校验

CLAUDE.md 约束的是 AI 生成阶段,但你还可以搭配 clang-tidy 或自定义脚本在提交阶段做二次校验。把校验规则写进 CLAUDE.md,AI 在生成代码时会主动考虑这些检查项:

## CI 校验规则(代码生成时必须满足)
- `clang-tidy` 检查:modernize-*, cppcoreguidelines-*, bugprone-*
- 自定义检查:代码中不得出现 `new ` 或 `delete ` 关键字
- 所有类必须具有明确的拷贝/移动语义声明(= default / = delete)

7.3 与 .clang-format 配合

CLAUDE.md 中声明格式化规范,配合 .clang-format 文件实现自动格式化,同时也让 AI 知道你的排版偏好:

## 格式化
- 使用项目根目录的 `.clang-format` 配置
- 缩进:4 空格,不使用 Tab
- 行宽限制:120 字符
- 大括号风格:Attach(不另起一行)

总结

CLAUDE.md 之于 Claude Code,就像 CMakeLists.txt 之于构建系统、「编码规范文档」之于团队协作——它是 AI 编程助手的规则锚点。对于 C++ 项目,锁定标准版本可以避免生成不兼容的语法,明确内存管理规范能从源头减少内存 Bug。两个约束叠加起来,让 AI 真正成为团队风格一致的协作者,而不是一个需要你反复纠正的「自由创作者」。

建议你现在就在项目根目录下创建 CLAUDE.md,先把 C++ 标准和内存规范写进去,后续再根据团队反馈逐步迭代。毕竟,好的规则不是一次写成的,而是在实践中打磨出来的

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐