svharness 0.8.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +290 -61
- package/dist/adapters/claude-code.js +1 -0
- package/dist/adapters/codechat.js +1 -0
- package/dist/adapters/cursor.js +1 -0
- package/dist/adapters/generic.js +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/opencode.js +17 -0
- package/dist/adapters/qoder.js +1 -0
- package/dist/commands/apply.js +456 -71
- package/dist/commands/convert.js +371 -0
- package/dist/commands/init.js +156 -11
- package/dist/commands/references-apply-skills.js +47 -0
- package/dist/commands/wizard.js +442 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/index.js +18 -0
- package/dist/config/load-config.js +54 -0
- package/dist/config/merge-options.js +115 -0
- package/dist/config/normalize.js +165 -0
- package/dist/config/save-config.js +40 -0
- package/dist/config/types.js +2 -0
- package/dist/core/agent-injector.js +58 -9
- package/dist/core/apply-project-entry.js +66 -0
- package/dist/core/build-project-entry.js +98 -0
- package/dist/core/doc-intake-paths.js +155 -0
- package/dist/core/extra-assets-intake.js +254 -0
- package/dist/core/markitdown-client.js +156 -0
- package/dist/core/next-steps.js +33 -22
- package/dist/core/project-ignore.js +53 -0
- package/dist/core/reference-apply-skills.js +35 -0
- package/dist/core/render-meta.js +2 -1
- package/dist/core/repomix-pack.js +3 -3
- package/dist/core/state.js +44 -24
- package/dist/index.js +211 -140
- package/dist/utils/harness-name.js +41 -0
- package/dist/utils/validate-args.js +147 -6
- package/dist/wiki/wikiTasksWriter.js +5 -6
- package/package.json +2 -1
- package/templates/_shared/apply-skills/harness-apply-skills-main.md +19 -78
- package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +5 -5
- package/templates/_shared/build-rules/harness-build-rule-chinese-only.md +5 -5
- package/templates/_shared/build-rules/harness-build-rule-convert-check.md +46 -0
- package/templates/_shared/build-rules/harness-build-rule-memory-write.md +1 -1
- package/templates/_shared/build-rules/harness-build-rule-orchestrator-flow.md +36 -10
- package/templates/_shared/build-rules/harness-build-rule-skills-tasks-output.md +3 -2
- package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +3 -3
- package/templates/_shared/build-rules/harness-build-rule-user-interaction.md +36 -16
- package/templates/_shared/build-skills/harness-build-skill-agent-env-merge.md +75 -0
- package/templates/_shared/build-skills/harness-build-skill-knowledge-builder.md +49 -85
- package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +35 -18
- package/templates/_shared/build-skills/harness-build-skill-references-intake.md +91 -0
- package/templates/_shared/build-skills/harness-build-skill-spec-builder.md +19 -9
- package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +24 -24
- package/templates/_shared/build-skills/harness-build-skills-main.md +83 -0
- package/templates/_shared/meta/AGENTS_APPLY.md.ejs +139 -0
- package/templates/_shared/meta/{AGENTS.md.ejs → AGENTS_BUILD.md.ejs} +7 -5
- package/templates/_shared/meta/CHANGELOG.md.ejs +3 -3
- package/templates/_shared/meta/README.md.ejs +11 -9
- package/templates/_shared/meta/harness.yaml.ejs +28 -7
- package/templates/_shared/skeleton/baseline/code/.gitkeep +1 -0
- package/templates/_shared/skeleton/baseline/wiki/.gitkeep +1 -0
- package/templates/_shared/skeleton/references/apply-skills-registry.example.yaml +11 -0
- package/templates/_shared/skeleton/references/md/.gitkeep +1 -0
- package/templates/_shared/skeleton/references/raw/.gitkeep +1 -0
- package/templates/_shared/skeleton/references/yaml/.gitkeep +1 -0
- package/templates/_shared/skeleton/requirements/md/.gitkeep +1 -0
- package/templates/_shared/skeleton/requirements/raw/.gitkeep +1 -0
- package/templates/_shared/skeleton/requirements/yaml/.gitkeep +1 -0
- package/templates/android-xml/skeleton/agent-env/skills/harness-android-cli/SKILL.md +88 -0
- package/templates/android-xml/skeleton/agent-env/skills/harness-android-service-patterns/SKILL.md +205 -0
- package/templates/android-xml/skeleton/agent-env/skills/harness-android-xml-architecture/SKILL.md +138 -0
- package/templates/android-xml/skeleton/agent-env/skills/harness-lifecycle-management/SKILL.md +158 -0
- package/templates/android-xml/skeleton/agent-env/skills/harness-xml-ui/SKILL.md +112 -0
- package/templates/cpp/skeleton/agent-env/skills/harness-cmake-build/SKILL.md +163 -0
- package/templates/cpp/skeleton/agent-env/skills/harness-cpp-architecture/SKILL.md +157 -0
- package/templates/cpp/skeleton/agent-env/skills/harness-cpp-concurrency/SKILL.md +180 -0
- package/templates/cpp/skeleton/agent-env/skills/harness-memory-safety/SKILL.md +163 -0
- package/templates/cpp/skeleton/agent-env/skills/harness-modern-cpp/SKILL.md +149 -0
- package/templates/python/skeleton/agent-env/skills/harness-async-patterns/SKILL.md +162 -0
- package/templates/python/skeleton/agent-env/skills/harness-python-architecture/SKILL.md +160 -0
- package/templates/python/skeleton/agent-env/skills/harness-python-package-structure/SKILL.md +210 -0
- package/templates/python/skeleton/agent-env/skills/harness-python-performance/SKILL.md +207 -0
- package/templates/python/skeleton/agent-env/skills/harness-python-testing/SKILL.md +198 -0
- package/templates/svharness.config.example.yaml +40 -0
- package/templates/web-react/skeleton/agent-env/skills/harness-react-architecture/SKILL.md +177 -0
- package/templates/web-react/skeleton/agent-env/skills/harness-react-performance/SKILL.md +177 -0
- package/templates/web-react/skeleton/agent-env/skills/harness-react-testing/SKILL.md +193 -0
- package/templates/web-react/skeleton/agent-env/skills/harness-react-ui-patterns/SKILL.md +257 -0
- package/templates/web-react/skeleton/agent-env/skills/harness-state-management/SKILL.md +189 -0
- package/templates/_shared/skeleton/assets/baseline/code/.gitkeep +0 -1
- package/templates/_shared/skeleton/assets/baseline/wiki/.gitkeep +0 -1
- package/templates/_shared/skeleton/assets/raw/.gitkeep +0 -1
- package/templates/_shared/skeleton/assets/requirements/.gitkeep +0 -1
- /package/templates/_shared/skeleton/{assets/baseline/repomix → agent-env/_incoming/skills}/.gitkeep +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-cmake-build
|
|
3
|
+
description: CMake 构建系统配置与管理。覆盖目标定义、依赖管理、测试配置、安装规则与跨平台构建。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CMake 构建系统
|
|
7
|
+
|
|
8
|
+
## 概述
|
|
9
|
+
|
|
10
|
+
使用 CMake 作为跨平台构建系统。遵循现代 CMake 最佳实践(目标驱动、IMPORTED 接口、别名命名)。
|
|
11
|
+
|
|
12
|
+
> **刚性约束已由 rules 加载:**
|
|
13
|
+
> - `seed-cmake-explicit-sources` — CMakeLists.txt 必须显式列出源文件,禁止 glob
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 根 CMakeLists.txt
|
|
18
|
+
|
|
19
|
+
```cmake
|
|
20
|
+
cmake_minimum_required(VERSION 3.20)
|
|
21
|
+
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
|
|
22
|
+
|
|
23
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
24
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
25
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
26
|
+
|
|
27
|
+
# 选项
|
|
28
|
+
option(BUILD_TESTS "Build unit tests" ON)
|
|
29
|
+
option(BUILD_EXAMPLES "Build examples" OFF)
|
|
30
|
+
|
|
31
|
+
# 添加子目录
|
|
32
|
+
add_subdirectory(src/core)
|
|
33
|
+
add_subdirectory(src/module_a)
|
|
34
|
+
|
|
35
|
+
if(BUILD_TESTS)
|
|
36
|
+
enable_testing()
|
|
37
|
+
add_subdirectory(tests)
|
|
38
|
+
endif()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 目标定义(现代 CMake)
|
|
42
|
+
|
|
43
|
+
```cmake
|
|
44
|
+
# src/core/CMakeLists.txt — Library 目标
|
|
45
|
+
|
|
46
|
+
# 只使用 add_library,不设置全局 include_directories
|
|
47
|
+
add_library(core
|
|
48
|
+
src/sensor_base.cpp
|
|
49
|
+
src/actuator_base.cpp
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# 公开头文件目录(被依赖者继承)
|
|
53
|
+
target_include_directories(core
|
|
54
|
+
PUBLIC
|
|
55
|
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
56
|
+
$<INSTALL_INTERFACE:include>
|
|
57
|
+
PRIVATE
|
|
58
|
+
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# 链接依赖
|
|
62
|
+
target_link_libraries(core
|
|
63
|
+
PUBLIC
|
|
64
|
+
# 接口依赖(传播给使用者)
|
|
65
|
+
PRIVATE
|
|
66
|
+
# 实现细节依赖
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 可执行目标
|
|
71
|
+
|
|
72
|
+
```cmake
|
|
73
|
+
# src/app/CMakeLists.txt
|
|
74
|
+
add_executable(my_app main.cpp)
|
|
75
|
+
|
|
76
|
+
target_link_libraries(my_app
|
|
77
|
+
PRIVATE
|
|
78
|
+
core
|
|
79
|
+
module_a
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 测试配置
|
|
84
|
+
|
|
85
|
+
```cmake
|
|
86
|
+
# tests/CMakeLists.txt
|
|
87
|
+
find_package(GTest REQUIRED)
|
|
88
|
+
|
|
89
|
+
add_executable(unit_tests
|
|
90
|
+
test_core_sensor.cpp
|
|
91
|
+
test_module_a.cpp
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
target_link_libraries(unit_tests
|
|
95
|
+
PRIVATE
|
|
96
|
+
core
|
|
97
|
+
module_a
|
|
98
|
+
GTest::gtest_main
|
|
99
|
+
GTest::gmock
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
target_compile_definitions(unit_tests PRIVATE UNIT_TEST)
|
|
103
|
+
|
|
104
|
+
# 自动注册测试
|
|
105
|
+
include(GoogleTest)
|
|
106
|
+
gtest_discover_tests(unit_tests)
|
|
107
|
+
|
|
108
|
+
add_test(NAME unit_tests COMMAND unit_tests)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 安装规则
|
|
112
|
+
|
|
113
|
+
```cmake
|
|
114
|
+
# 安装库与头文件
|
|
115
|
+
install(TARGETS core module_a
|
|
116
|
+
EXPORT MyProjectTargets
|
|
117
|
+
LIBRARY DESTINATION lib
|
|
118
|
+
ARCHIVE DESTINATION lib
|
|
119
|
+
RUNTIME DESTINATION bin
|
|
120
|
+
INCLUDES DESTINATION include
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
install(DIRECTORY include/ DESTINATION include)
|
|
124
|
+
|
|
125
|
+
# 导出包(供 find_package 使用)
|
|
126
|
+
install(EXPORT MyProjectTargets
|
|
127
|
+
FILE MyProjectTargets.cmake
|
|
128
|
+
NAMESPACE MyProject::
|
|
129
|
+
DESTINATION lib/cmake/MyProject
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 跨平台
|
|
134
|
+
|
|
135
|
+
```cmake
|
|
136
|
+
# 编译器特定设置
|
|
137
|
+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
|
138
|
+
target_compile_options(my_target PRIVATE /W4 /WX)
|
|
139
|
+
else()
|
|
140
|
+
target_compile_options(my_target PRIVATE -Wall -Wextra -Werror -Wpedantic)
|
|
141
|
+
endif()
|
|
142
|
+
|
|
143
|
+
# 平台检测
|
|
144
|
+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
145
|
+
target_link_libraries(my_target PRIVATE pthread)
|
|
146
|
+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
|
147
|
+
# Android NDK 特定配置
|
|
148
|
+
endif()
|
|
149
|
+
|
|
150
|
+
# 显式列出源文件(禁止 GLOB)
|
|
151
|
+
set(MODULE_A_SOURCES
|
|
152
|
+
src/module_a/processor.cpp
|
|
153
|
+
src/module_a/validator.cpp
|
|
154
|
+
src/module_a/utils.cpp
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 相关规则
|
|
161
|
+
|
|
162
|
+
- `seed-cmake-explicit-sources` — 显式源文件列表
|
|
163
|
+
- `seed-no-cyclic-deps` — 循环依赖检测
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-cpp-architecture
|
|
3
|
+
description: C++ 项目架构与模块化设计指引。覆盖目录结构、分层职责、依赖管理、接口设计与循环依赖预防。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# C++ 架构设计指引
|
|
7
|
+
|
|
8
|
+
## 概述
|
|
9
|
+
|
|
10
|
+
本项目采用模块化分层架构。组件间通过明确接口通信,禁止循环依赖,保持低耦合高内聚。
|
|
11
|
+
|
|
12
|
+
> **刚性约束已由 rules 加载,本技能不再重复。** 详见:
|
|
13
|
+
> - `seed-include-layering` — include 分层顺序与可见性约束
|
|
14
|
+
> - `seed-no-cyclic-deps` — 禁止模块间循环依赖
|
|
15
|
+
> - `seed-header-guards` — 头文件保护符强制
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 项目结构
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
project/
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── core/ # 核心抽象与接口
|
|
25
|
+
│ │ ├── include/core/
|
|
26
|
+
│ │ │ ├── ISensor.h
|
|
27
|
+
│ │ │ └── IActuator.h
|
|
28
|
+
│ │ └── CMakeLists.txt
|
|
29
|
+
│ ├── module_a/ # 功能模块 A
|
|
30
|
+
│ │ ├── include/module_a/
|
|
31
|
+
│ │ ├── src/
|
|
32
|
+
│ │ └── CMakeLists.txt
|
|
33
|
+
│ ├── module_b/ # 功能模块 B
|
|
34
|
+
│ │ └── ...
|
|
35
|
+
│ └── app/ # 应用入口
|
|
36
|
+
│ ├── main.cpp
|
|
37
|
+
│ └── CMakeLists.txt
|
|
38
|
+
├── tests/
|
|
39
|
+
│ ├── unit/
|
|
40
|
+
│ └── integration/
|
|
41
|
+
├── third_party/ # 第三方依赖
|
|
42
|
+
├── CMakeLists.txt # 根 CMake
|
|
43
|
+
└── README.md
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 分层依赖规则
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
App(主入口)
|
|
50
|
+
│ 依赖所有模块
|
|
51
|
+
▼
|
|
52
|
+
Core(抽象接口)
|
|
53
|
+
│ 零依赖或仅依赖标准库
|
|
54
|
+
▼
|
|
55
|
+
Module A ←──→ Module B(禁止循环依赖)
|
|
56
|
+
│ │
|
|
57
|
+
▼ ▼
|
|
58
|
+
Core(接口层)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| 层级 | 职责 | 可依赖 |
|
|
62
|
+
|------|------|--------|
|
|
63
|
+
| **App** | 初始化、依赖注入、生命周期 | 所有模块 |
|
|
64
|
+
| **Module** | 业务逻辑实现 | Core 接口、其他模块(单向) |
|
|
65
|
+
| **Core** | 纯抽象接口、数据结构 | 标准库 |
|
|
66
|
+
|
|
67
|
+
## 接口设计
|
|
68
|
+
|
|
69
|
+
```cpp
|
|
70
|
+
// core/include/core/ISensor.h
|
|
71
|
+
#pragma once
|
|
72
|
+
|
|
73
|
+
#include <memory>
|
|
74
|
+
#include <optional>
|
|
75
|
+
#include <vector>
|
|
76
|
+
|
|
77
|
+
namespace core {
|
|
78
|
+
|
|
79
|
+
struct SensorData {
|
|
80
|
+
double value;
|
|
81
|
+
uint64_t timestamp_us;
|
|
82
|
+
bool valid;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
class ISensor {
|
|
86
|
+
public:
|
|
87
|
+
virtual ~ISensor() = default;
|
|
88
|
+
|
|
89
|
+
// 纯虚接口 — 禁止定义成员变量
|
|
90
|
+
virtual std::optional<SensorData> read() = 0;
|
|
91
|
+
virtual bool configure(const std::string& key, double value) = 0;
|
|
92
|
+
virtual std::string name() const = 0;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// 工厂函数(非类方法)
|
|
96
|
+
std::unique_ptr<ISensor> CreateTemperatureSensor();
|
|
97
|
+
|
|
98
|
+
} // namespace core
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 依赖注入
|
|
102
|
+
|
|
103
|
+
```cpp
|
|
104
|
+
class TemperatureMonitor {
|
|
105
|
+
public:
|
|
106
|
+
// 通过构造函数注入依赖
|
|
107
|
+
explicit TemperatureMonitor(std::unique_ptr<core::ISensor> sensor)
|
|
108
|
+
: sensor_(std::move(sensor)) {}
|
|
109
|
+
|
|
110
|
+
double getCurrentTemperature() {
|
|
111
|
+
auto data = sensor_->read();
|
|
112
|
+
return data.has_value() ? data->value : 0.0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private:
|
|
116
|
+
std::unique_ptr<core::ISensor> sensor_; // 所有权唯一
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## PIMPL 模式(隐藏实现细节)
|
|
121
|
+
|
|
122
|
+
```cpp
|
|
123
|
+
// public/include/module_a/Processor.h
|
|
124
|
+
#pragma once
|
|
125
|
+
|
|
126
|
+
#include <memory>
|
|
127
|
+
|
|
128
|
+
namespace module_a {
|
|
129
|
+
|
|
130
|
+
class Processor {
|
|
131
|
+
public:
|
|
132
|
+
Processor();
|
|
133
|
+
~Processor();
|
|
134
|
+
|
|
135
|
+
Processor(const Processor&) = delete;
|
|
136
|
+
Processor& operator=(const Processor&) = delete;
|
|
137
|
+
Processor(Processor&&) noexcept;
|
|
138
|
+
Processor& operator=(Processor&&) noexcept;
|
|
139
|
+
|
|
140
|
+
void process();
|
|
141
|
+
void setConfig(const std::string& config);
|
|
142
|
+
|
|
143
|
+
private:
|
|
144
|
+
class Impl;
|
|
145
|
+
std::unique_ptr<Impl> impl_;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
} // namespace module_a
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 相关规则
|
|
154
|
+
|
|
155
|
+
- `seed-include-layering` — include 分层顺序
|
|
156
|
+
- `seed-no-cyclic-deps` — 循环依赖禁止
|
|
157
|
+
- `seed-header-guards` — 头文件保护符
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-cpp-concurrency
|
|
3
|
+
description: C++ 并发与线程安全模式。覆盖 std::thread、互斥锁、条件变量、std::async、线程池与无锁编程指南。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# C++ 并发编程
|
|
7
|
+
|
|
8
|
+
## 概述
|
|
9
|
+
|
|
10
|
+
正确使用 C++ 并发设施,遵循线程安全原则,避免数据竞争与死锁。
|
|
11
|
+
|
|
12
|
+
> **相关规则:**
|
|
13
|
+
> - `seed-raii` — RAII 管理互斥锁生命周期
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 基本线程管理
|
|
18
|
+
|
|
19
|
+
```cpp
|
|
20
|
+
#include <thread>
|
|
21
|
+
#include <iostream>
|
|
22
|
+
|
|
23
|
+
void worker(int id) {
|
|
24
|
+
std::cout << "Worker " << id << " started\n";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
int main() {
|
|
28
|
+
std::thread t1(worker, 1);
|
|
29
|
+
std::thread t2(worker, 2);
|
|
30
|
+
|
|
31
|
+
// 等待完成
|
|
32
|
+
t1.join();
|
|
33
|
+
t2.join();
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 互斥锁(RAII 封装)
|
|
39
|
+
|
|
40
|
+
```cpp
|
|
41
|
+
#include <mutex>
|
|
42
|
+
|
|
43
|
+
class SensorCache {
|
|
44
|
+
public:
|
|
45
|
+
void update(double value) {
|
|
46
|
+
std::lock_guard<std::mutex> lock(mutex_); // 异常安全
|
|
47
|
+
cache_ = value;
|
|
48
|
+
++version_;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
std::pair<double, uint64_t> read() const {
|
|
52
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
53
|
+
return {cache_, version_};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private:
|
|
57
|
+
mutable std::mutex mutex_; // mutable 允许 const 方法加锁
|
|
58
|
+
double cache_ = 0.0;
|
|
59
|
+
uint64_t version_ = 0;
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 读写锁(读频繁场景)
|
|
64
|
+
|
|
65
|
+
```cpp
|
|
66
|
+
#include <shared_mutex>
|
|
67
|
+
|
|
68
|
+
class ConfigStore {
|
|
69
|
+
public:
|
|
70
|
+
std::string get(const std::string& key) const {
|
|
71
|
+
std::shared_lock lock(mutex_); // 共享读
|
|
72
|
+
auto it = map_.find(key);
|
|
73
|
+
return it != map_.end() ? it->second : "";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void set(const std::string& key, std::string value) {
|
|
77
|
+
std::unique_lock lock(mutex_); // 独占写
|
|
78
|
+
map_[key] = std::move(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private:
|
|
82
|
+
mutable std::shared_mutex mutex_;
|
|
83
|
+
std::map<std::string, std::string> map_;
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 条件变量
|
|
88
|
+
|
|
89
|
+
```cpp
|
|
90
|
+
#include <condition_variable>
|
|
91
|
+
|
|
92
|
+
class MessageQueue {
|
|
93
|
+
public:
|
|
94
|
+
void push(int value) {
|
|
95
|
+
{
|
|
96
|
+
std::lock_guard lock(mutex_);
|
|
97
|
+
queue_.push(value);
|
|
98
|
+
}
|
|
99
|
+
cv_.notify_one();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
int pop() {
|
|
103
|
+
std::unique_lock lock(mutex_);
|
|
104
|
+
cv_.wait(lock, [this] { return !queue_.empty(); });
|
|
105
|
+
int value = queue_.front();
|
|
106
|
+
queue_.pop();
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private:
|
|
111
|
+
std::mutex mutex_;
|
|
112
|
+
std::condition_variable cv_;
|
|
113
|
+
std::queue<int> queue_;
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## std::async — 简化异步任务
|
|
118
|
+
|
|
119
|
+
```cpp
|
|
120
|
+
#include <future>
|
|
121
|
+
|
|
122
|
+
// 异步获取传感器数据
|
|
123
|
+
std::future<SensorData> async_sensor_read(ISensor& sensor) {
|
|
124
|
+
return std::async(std::launch::async, [&sensor] {
|
|
125
|
+
return sensor.read();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 使用
|
|
130
|
+
ISensor& sensor = getSensor();
|
|
131
|
+
auto future = async_sensor_read(sensor);
|
|
132
|
+
|
|
133
|
+
// 执行其他操作...
|
|
134
|
+
|
|
135
|
+
// 等待结果(带超时)
|
|
136
|
+
if (future.wait_for(std::chrono::milliseconds(100)) ==
|
|
137
|
+
std::future_status::ready) {
|
|
138
|
+
auto data = future.get();
|
|
139
|
+
process(data);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 线程安全单例
|
|
144
|
+
|
|
145
|
+
```cpp
|
|
146
|
+
class Logger {
|
|
147
|
+
public:
|
|
148
|
+
static Logger& instance() {
|
|
149
|
+
static Logger log; // C++11 起线程安全(magic static)
|
|
150
|
+
return log;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void log(const std::string& msg) {
|
|
154
|
+
std::lock_guard lock(mutex_);
|
|
155
|
+
// 写入日志...
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private:
|
|
159
|
+
Logger() = default; // 私有构造
|
|
160
|
+
Logger(const Logger&) = delete;
|
|
161
|
+
Logger& operator=(const Logger&) = delete;
|
|
162
|
+
std::mutex mutex_;
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 注意事项
|
|
167
|
+
|
|
168
|
+
| 陷阱 | 说明 | 解决方案 |
|
|
169
|
+
|------|------|---------|
|
|
170
|
+
| **死锁** | 多个锁交叉顺序加锁 | 固定加锁顺序或使用 std::lock() |
|
|
171
|
+
| **数据竞争** | 非原子变量的并发读写 | 使用 mutex 或 std::atomic |
|
|
172
|
+
| **假唤醒** | 条件变量无故唤醒 | wait() 必须使用谓词重载 |
|
|
173
|
+
| **线程泄漏** | detach 后线程未完成 | 优先使用 join,避免 detach |
|
|
174
|
+
| **异常传播** | 线程内异常无法传出 | 用 std::future 或包装错误码 |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 相关规则
|
|
179
|
+
|
|
180
|
+
- `seed-raii` — RAII 管理锁生命周期
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-memory-safety
|
|
3
|
+
description: C++ RAII 与内存安全最佳实践。覆盖智能指针使用、资源管理、异常安全、移动语义与防止内存泄漏。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RAII 与内存安全
|
|
7
|
+
|
|
8
|
+
## 概述
|
|
9
|
+
|
|
10
|
+
RAII(Resource Acquisition Is Initialization)是 C++ 核心资源管理范式。资源在构造函数中获取,在析构函数中释放,确保异常安全与无泄漏。
|
|
11
|
+
|
|
12
|
+
> **刚性约束已由 rules 加载:**
|
|
13
|
+
> - `seed-raii` — 禁止裸 new/delete,禁止裸 malloc/free
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 资源管理三原则
|
|
18
|
+
|
|
19
|
+
### 1. 动态内存 → 智能指针
|
|
20
|
+
|
|
21
|
+
```cpp
|
|
22
|
+
// 正确:智能指针
|
|
23
|
+
auto buffer = std::make_unique<uint8_t[]>(1024);
|
|
24
|
+
auto config = std::make_shared<Configuration>();
|
|
25
|
+
|
|
26
|
+
// 错误:裸指针
|
|
27
|
+
uint8_t* buf = new uint8_t[1024]; // 禁止
|
|
28
|
+
delete[] buf; // 禁止
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. 文件 → RAII 包装
|
|
32
|
+
|
|
33
|
+
```cpp
|
|
34
|
+
// 正确:std::ifstream/ofstream 自动关闭
|
|
35
|
+
std::ifstream file(path);
|
|
36
|
+
if (!file) {
|
|
37
|
+
throw std::runtime_error("Failed to open file");
|
|
38
|
+
}
|
|
39
|
+
// 读取... 作用域结束自动关闭
|
|
40
|
+
|
|
41
|
+
// 错误:手动配对
|
|
42
|
+
FILE* f = fopen(path, "r"); // 禁止
|
|
43
|
+
// ...
|
|
44
|
+
fclose(f); // 禁止
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. 锁 → RAII 锁守卫
|
|
48
|
+
|
|
49
|
+
```cpp
|
|
50
|
+
// 正确:异常安全
|
|
51
|
+
{
|
|
52
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
53
|
+
shared_data_ = new_value;
|
|
54
|
+
// 自动解锁,即使异常
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 错误:手动 lock/unlock
|
|
58
|
+
mutex_.lock(); // 禁止
|
|
59
|
+
shared_data_ = new_value;
|
|
60
|
+
mutex_.unlock(); // 异常时不会执行
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 异常安全
|
|
64
|
+
|
|
65
|
+
```cpp
|
|
66
|
+
// 强异常安全保证:要么完全成功,要么回滚
|
|
67
|
+
class Account {
|
|
68
|
+
public:
|
|
69
|
+
void transfer(Account& other, double amount) {
|
|
70
|
+
// 先复制
|
|
71
|
+
Account temp(*this);
|
|
72
|
+
temp.balance_ -= amount;
|
|
73
|
+
other.balance_ += amount;
|
|
74
|
+
|
|
75
|
+
// 全部成功后原子交换
|
|
76
|
+
std::swap(*this, temp); // noexcept
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private:
|
|
80
|
+
double balance_ = 0.0;
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 移动语义
|
|
85
|
+
|
|
86
|
+
```cpp
|
|
87
|
+
// 移动构造函数与移动赋值
|
|
88
|
+
class Buffer {
|
|
89
|
+
public:
|
|
90
|
+
Buffer() : data_(nullptr), size_(0) {}
|
|
91
|
+
|
|
92
|
+
// 移动构造
|
|
93
|
+
Buffer(Buffer&& other) noexcept
|
|
94
|
+
: data_(std::exchange(other.data_, nullptr))
|
|
95
|
+
, size_(std::exchange(other.size_, 0)) {}
|
|
96
|
+
|
|
97
|
+
// 移动赋值
|
|
98
|
+
Buffer& operator=(Buffer&& other) noexcept {
|
|
99
|
+
if (this != &other) {
|
|
100
|
+
delete[] data_;
|
|
101
|
+
data_ = std::exchange(other.data_, nullptr);
|
|
102
|
+
size_ = std::exchange(other.size_, 0);
|
|
103
|
+
}
|
|
104
|
+
return *this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
~Buffer() {
|
|
108
|
+
delete[] data_;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 禁止拷贝(资源唯一所有权)
|
|
112
|
+
Buffer(const Buffer&) = delete;
|
|
113
|
+
Buffer& operator=(const Buffer&) = delete;
|
|
114
|
+
|
|
115
|
+
private:
|
|
116
|
+
uint8_t* data_;
|
|
117
|
+
size_t size_;
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 自定义 RAII 包装
|
|
122
|
+
|
|
123
|
+
```cpp
|
|
124
|
+
// 通用 RAII 包装(任何需要释放的资源)
|
|
125
|
+
template <typename T, auto Deleter>
|
|
126
|
+
class ScopedResource {
|
|
127
|
+
public:
|
|
128
|
+
explicit ScopedResource(T resource) : resource_(resource) {}
|
|
129
|
+
|
|
130
|
+
~ScopedResource() {
|
|
131
|
+
if (resource_) {
|
|
132
|
+
Deleter(resource_);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
ScopedResource(const ScopedResource&) = delete;
|
|
137
|
+
ScopedResource& operator=(const ScopedResource&) = delete;
|
|
138
|
+
|
|
139
|
+
T get() const { return resource_; }
|
|
140
|
+
|
|
141
|
+
private:
|
|
142
|
+
T resource_;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// 使用:包装 C API 句柄
|
|
146
|
+
// auto fd = ScopedResource<int, close>(open(path, O_RDONLY));
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## 内存泄漏预防清单
|
|
150
|
+
|
|
151
|
+
- [ ] 所有 `new` 配对 `delete`(或使用智能指针)
|
|
152
|
+
- [ ] 基类析构函数声明为 `virtual` 或 `protected`
|
|
153
|
+
- [ ] 资源管理类遵守 **三五法则**(Rule of Three/Five)
|
|
154
|
+
- [ ] 容器使用 `std::vector` / `std::array` 而非裸数组
|
|
155
|
+
- [ ] 字符串使用 `std::string` 而非 `char*`
|
|
156
|
+
- [ ] 跨 DLL 边界传递使用 `std::shared_ptr`(小心 ABI)
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 相关规则
|
|
161
|
+
|
|
162
|
+
- `seed-raii` — RAII 与内存安全强制
|
|
163
|
+
- `seed-header-guards` — 头文件保护符
|