plugins/languages/cpp/skills/memory/SKILL.md
C++ memory management with modern RAII: std::unique_ptr / shared_ptr / weak_ptr, custom deleters, scope guards, allocators, std::span, std::string_view, leak diagnosis. Use when designing resource ownership, wrapping C APIs, optimizing allocations, or diagnosing memory leaks. Also triggers on "智能指针", "unique_ptr", "shared_ptr", "RAII", "scope guard", "自定义 deleter", "allocator", "内存泄漏", "use-after-free", "Valgrind", "ASan 报告".
npx skillsauth add lazygophers/ccplugin cpp-memoryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
所有动态资源走 RAII,使用 cpp-core 的强制约定为基线,并在此扩展所有权设计与诊断。
unique_ptr — 独占所有权(默认选择,零开销)
shared_ptr — 共享所有权(必要时;引用计数有开销)
weak_ptr — 打破循环、观察者引用
raw pointer — 仅非所有权引用,绝不持有
std::span — 连续内存非所有权视图
std::string_view — 字符串非所有权视图
选择优先级:栈对象 > unique_ptr > shared_ptr。共享只在多处需要延长生命期时使用。
// 构造:必须 make_unique,禁裸 new
auto widget = std::make_unique<Widget>(args...);
// 转移所有权
auto moved = std::move(widget); // widget 变 nullptr
// 工厂返回
std::unique_ptr<Base> create(Type t) {
switch (t) {
case Type::A: return std::make_unique<DerivedA>();
case Type::B: return std::make_unique<DerivedB>();
}
return nullptr;
}
// 数组特化
auto buffer = std::make_unique<uint8_t[]>(size);
buffer[0] = 0x42;
// make_shared:单次分配(控制块 + 对象同块)
auto resource = std::make_shared<Resource>(args...);
// 别名构造:共享所有权但指向成员
auto member = std::shared_ptr<Member>(resource, &resource->member);
// enable_shared_from_this 模式
class Session : public std::enable_shared_from_this<Session> {
void start() {
auto self = shared_from_this();
async_op([self](auto result) { self->handle(std::move(result)); });
}
};
struct Node {
std::vector<std::shared_ptr<Node>> children;
std::weak_ptr<Node> parent; // 不参与计数,避免环
void notify_parent() {
if (auto p = parent.lock()) {
p->on_child_event();
}
}
};
// 通用模板:custom deleter via unique_ptr
template<typename T, auto Deleter>
using CResource = std::unique_ptr<T, decltype([](T* p) noexcept { Deleter(p); })>;
using FileHandle = CResource<FILE, fclose>;
using SqliteDB = CResource<sqlite3, sqlite3_close>;
FileHandle open_file(const char* path) {
FileHandle f(std::fopen(path, "rb"));
if (!f) throw std::system_error(errno, std::generic_category());
return f;
}
C++23 暂未纳入 std::scope_exit(P0052 仍在路上)。当前实现:
template<typename F>
class ScopeExit {
F fn_;
bool active_ = true;
public:
explicit ScopeExit(F f) noexcept : fn_(std::move(f)) {}
~ScopeExit() { if (active_) fn_(); }
void dismiss() noexcept { active_ = false; }
ScopeExit(ScopeExit&& o) noexcept
: fn_(std::move(o.fn_)), active_(std::exchange(o.active_, false)) {}
ScopeExit(const ScopeExit&) = delete;
ScopeExit& operator=(const ScopeExit&) = delete;
};
// 使用
void process() {
auto* ctx = acquire_legacy_ctx();
ScopeExit guard([ctx] { release_legacy_ctx(ctx); });
use(ctx);
// 异常或正常返回都会 release
}
// std::span:连续内存视图
void process(std::span<const float> data);
void modify (std::span<float> data);
// std::string_view:字符串视图(注意生命期)
void parse(std::string_view input);
// std::mdspan(C++23):多维视图
void transform(std::mdspan<float, std::dextents<size_t, 2>> mat);
字符串视图陷阱:绝不返回指向临时对象的 string_view。
| 需求 | 容器 | 原因 |
|------|------|------|
| 默认动态序列 | std::vector<T> | 缓存友好、连续 |
| 编译期固定大小 | std::array<T, N> | 栈上分配 |
| 有序键值 | std::map<K, V> | O(log n),迭代器稳定 |
| 哈希键值 | std::unordered_map<K, V> | 平均 O(1) |
| 缓存友好键值 | std::flat_map<K, V> (C++23) | 连续存储,比 map 快 2–10× |
| 双端队列 | std::deque<T> | 两端 O(1) |
| 非所有权视图 | std::span<T> | 零拷贝 |
#include <memory_resource>
// 单调缓冲区:分配快、批量释放
std::array<std::byte, 16384> buffer;
std::pmr::monotonic_buffer_resource arena(buffer.data(), buffer.size());
std::pmr::vector<int> v(&arena);
v.reserve(1024);
// 函数返回时整片释放
适用场景:短生命期对象 + 高频分配(编译器、JSON 解析、游戏帧)。
# AddressSanitizer:use-after-free、heap-buffer-overflow、leak
g++ -fsanitize=address -fno-omit-frame-pointer -g -O1 src/*.cpp
ASAN_OPTIONS=detect_leaks=1:strict_string_checks=1 ./a.out
# Valgrind memcheck
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./a.out
# heaptrack:低开销 heap profile
heaptrack ./a.out
heaptrack --analyze heaptrack.a.out.*.gz
| 借口 | 检查项 |
|------|--------|
| "裸指针没事" | 是否用智能指针表达所有权? |
| "new/delete 更清晰" | 是否换 make_unique / make_shared? |
| "全部 shared_ptr" | unique_ptr 是否够用?引用计数开销是否必要? |
| "不需要 scope guard" | 异常路径资源是否必释放? |
| "C API 手动 free 即可" | 是否包成 custom deleter unique_ptr? |
| "string_view 总是安全" | 是否引用了临时字符串? |
unique_ptr 默认,shared_ptr 仅多端共享weak_ptr 切断unique_ptr 包装std::span / std::string_viewreserve() 预分配new/delete、malloc/free、裸 owning 指针tools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。