基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ROCm/rocprofiler-systems-skills --skill programming-cpp命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Given a TheRock nightly build (URL or run-id), return the rocm-systems pin_sha used in that build
Check whether a given rocm-systems commit is included in a specific TheRock nightly build
Find the first TheRock nightly build that includes a given rocm-systems commit
| name | programming-cpp |
| description | C++ programming skill based on C++ Core Guidelines - use for implementing C++ code |
Use this skill when writing or modifying C++ code.
Follow the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) as the primary reference for best practices.C++17 Standard. This project uses C++17. Use only features available in C++17. Do NOT use C++20 features (concepts, ranges, std::span, etc.).
Compile-time execution is a PRIORITY. If code CAN be executed at compile time, it SHOULD be. Use constexpr, if constexpr, template metaprogramming. Move as much computation as possible from runtime to compile time.
Performance is critical. This is performance-sensitive software. Always consider performance implications. Prefer zero-cost abstractions, avoid unnecessary allocations, and be cache-friendly.
All code MUST be unit testable. Use Dependency Injection and/or Policy-based design to achieve testability.
Guidelines override existing code style. If you see existing code that violates the rules in this skill, apply these guidelines first and ignore the current project style. Do NOT propagate bad patterns just because they exist in the codebase.
T*) or reference (T&)constexprnoexceptT* or T& arguments rather than smart pointersconstconstunique_ptr<T> to transfer ownership where a pointer is neededshared_ptr<T> to share ownershipstructs or classes)class if the class has an invariant; use struct if the data members can vary independently=delete any copy, move, or destructor function, define or =delete them all (Rule of 0/5)=default if you have to be explicit about using the default semanticsvirtual, override, or finalunique_ptr or shared_ptr to avoid forgetting to delete objects created using newT*) is non-owningT&) is non-owningmalloc() and free()new and delete explicitlyunique_ptr or shared_ptr to represent ownershipunique_ptr over shared_ptr unless you need to share ownershipmake_shared() to make shared_ptrsmake_unique() to make unique_ptrsswap, and exception type copy/move construction must never failtry/catchThis is performance-critical software. Apply these rules from C++ Core Guidelines - Performance:
// BAD: Allocations in hot path
void process_items(const std::vector<item>& items) {
for (const auto& item : items) {
auto result = std::make_unique<result_t>(); // Allocation per iteration!
// ...
}
}
// GOOD: Pre-allocate or reuse
void process_items(const std::vector<item>& items) {
result_t result; // Stack allocation, reused
for (const auto& item : items) {
result.reset();
// ...
}
}
// GOOD: Reserve capacity
std::vector<int> results;
results.reserve(items.size()); // Avoid reallocations
// BAD: Unnecessary copy
void process(std::vector<int> data) { } // Copies entire vector
// GOOD: Pass by const reference
void process(const std::vector<int>& data) { }
// GOOD: Pass by value if you need to modify/own it (enables move)
void take_ownership(std::vector<int> data) {
m_data = std::move(data);
}
// BAD: Return by const reference from temporary
const std::string& get_name() { return m_name; } // OK
const std::string& bad() { return std::string("temp"); } // Dangling!
// GOOD: Return by value (RVO/NRVO applies)
std::string get_computed_name() {
std::string result = compute();
return result; // Move or RVO, no copy
}
// Use std::move when transferring ownership
std::vector<int> source = get_data();
process(std::move(source)); // source is now empty
// Implement move constructor/assignment for heavy classes
class heavy_resource {
public:
heavy_resource(heavy_resource&& other) noexcept
: m_data(std::exchange(other.m_data, nullptr)) {}
heavy_resource& operator=(heavy_resource&& other) noexcept {
if (this != &other) {
delete m_data;
m_data = std::exchange(other.m_data, nullptr);
}
return *this;
}
};
// BAD: Cache-unfriendly (pointer chasing)
struct node {
node* next;
int data;
};
// GOOD: Cache-friendly (contiguous memory)
std::vector<int> data; // Contiguous, prefetch-friendly
// BAD: Column-major access in row-major array
for (int col = 0; col < cols; ++col)
for (int row = 0; row < rows; ++row)
matrix[row][col] = 0; // Cache miss every access!
// GOOD: Row-major access
for (int row = 0; row < rows; ++row)
for (int col = 0; col < cols; ++col)
matrix[row][col] = 0; // Sequential access
// Prefer constexpr for compile-time computation
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int fact_10 = factorial(10); // Computed at compile time
// Use if constexpr for compile-time branching
template<typename T>
void process(T value) {
if constexpr (std::is_integral_v<T>) {
// Integer-specific code
} else {
// Other types
}
}
// Prefer templates over virtual for known types (no vtable lookup)
template<typename Handler>
void process(Handler& h) { h.handle(); } // Inlined, no virtual call
| Pitfall | Solution |
|---|---|
std::endl in loops | Use '\n' (no flush) |
std::map for small sets | Use std::vector + linear search for < 20 elements |
| String concatenation in loops | Use std::ostringstream or pre-reserve |
Unnecessary shared_ptr | Use unique_ptr (no atomic refcount) |
| Virtual calls in hot loops | Use CRTP or templates |
std::function in hot path | Use templates or function pointers |
| Exceptions for control flow | Use return values or std::optional |
| Copying in range-for | Use const auto& |
const&, small by valuestd::move when transferring ownershipreserve() when size is knownconstexpr for compile-time computationsAll C++ code must be designed for unit testing. Use these patterns:
Inject dependencies through constructor or setter instead of creating them internally:
// BAD: Hard to test - creates its own dependency
class order_processor {
database m_db; // Creates concrete database
public:
void process(const order& o) {
m_db.save(o); // Can't mock this
}
};
// GOOD: Testable - dependency injected via interface
class i_database {
public:
virtual ~i_database() = default;
virtual void save(const order& o) = 0;
};
class order_processor {
i_database& m_db; // Injected dependency
public:
explicit order_processor(i_database& db) : m_db(db) {}
void process(const order& o) {
m_db.save(o); // Can be mocked in tests
}
};
// Test with mock
class mock_database : public i_database {
public:
void save(const order& o) override { /* verify call */ }
};
Use templates with policy classes for compile-time dependency injection:
// Policy-based design - zero runtime overhead
template<typename DatabasePolicy>
class order_processor {
DatabasePolicy m_db;
public:
void process(const order& o) {
m_db.save(o);
}
};
// Production policy
struct production_database {
void save(const order& o) { /* real implementation */ }
};
// Test policy