Skip to main content

programming-cpp

C++ programming skill based on C++ Core Guidelines - use for implementing C++ code

インストールへ移動

ソース情報

リポジトリ
ROCm/rocprofiler-systems-skills
ソースの最終更新活動
2026年5月6日 19:51
検出された SKILL.md の言語
英語
スター
4
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
programming-cpp
description
C++ programming skill based on C++ Core Guidelines - use for implementing C++ code
# C++ Programming Skill Use this skill when writing or modifying C++ code. <IMPORTANT> 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. </IMPORTANT> ## Philosophy (from C++ Core Guidelines) - **P.1**: Express ideas directly in code - **P.2**: Write in ISO Standard C++ - **P.3**: Express intent - **P.4**: Ideally, a program should be statically type safe - **P.5**: Prefer compile-time checking to run-time checking - **P.6**: What cannot be checked at compile time should be checkable at run time - **P.9**: Don't waste time or space - **P.10**: Prefer immutable data to mutable data - **P.11**: Encapsulate messy constructs, rather than spreading through the code ## Interfaces - **I.1**: Make interfaces explicit - **I.2**: Avoid non-const global variables - **I.3**: Avoid singletons - **I.4**: Make interfaces precisely and strongly typed - **I.11**: Never transfer ownership by a raw pointer (`T*`) or reference (`T&`) - **I.13**: Do not pass an array as a single pointer ## Functions - **F.1**: "Package" meaningful operations as carefully named functions - **F.2**: A function should perform a single logical operation - **F.3**: Keep functions short and simple - **F.4**: If a function might have to be evaluated at compile time, declare it `constexpr` - **F.6**: If your function must not throw, declare it `noexcept` - **F.7**: For general use, take `T*` or `T&` arguments rather than smart pointers - **F.15**: Prefer simple and conventional ways of passing information - **F.16**: For "in" parameters, pass cheaply-copied types by value and others by reference to `const` - **F.17**: For "in-out" parameters, pass by reference to non-`const` - **F.20**: For "out" output values, prefer return values to output parameters - **F.21**: To return multiple "out" values, prefer returning a struct or tuple - **F.26**: Use a `unique_ptr<T>` to transfer ownership where a pointer is needed - **F.27**: Use a `shared_ptr<T>` to share ownership ## Classes and Class Hierarchies - **C.1**: Organize related data into structures (`struct`s or `class`es) - **C.2**: Use `class` if the class has an invariant; use `struct` if the data members can vary independently - **C.4**: Make a function a member only if it needs direct access to the representation of a class - **C.7**: Don't define a class or enum and declare a variable of its type in the same statement - **C.9**: Minimize exposure of members - **C.20**: If you can avoid defining default operations, do - **C.21**: If you define or `=delete` any copy, move, or destructor function, define or `=delete` them all (Rule of 0/5) - **C.35**: A base class destructor should be either public and virtual, or protected and non-virtual - **C.47**: Define and initialize data members in the order of member declaration - **C.48**: Prefer default member initializers to member initializers in constructors for constant initializers - **C.49**: Prefer initialization to assignment in constructors - **C.80**: Use `=default` if you have to be explicit about using the default semantics - **C.82**: Don't call virtual functions in constructors and destructors - **C.128**: Virtual functions should specify exactly one of `virtual`, `override`, or `final` - **C.131**: Avoid trivial getters and setters - **C.149**: Use `unique_ptr` or `shared_ptr` to avoid forgetting to `delete` objects created using `new` ## Resource Management - **R.1**: Manage resources automatically using resource handles and RAII - **R.2**: In interfaces, use raw pointers to denote individual objects (only) - **R.3**: A raw pointer (`T*`) is non-owning - **R.4**: A raw reference (`T&`) is non-owning - **R.5**: Prefer scoped objects, don't heap-allocate unnecessarily - **R.10**: Avoid `malloc()` and `free()` - **R.11**: Avoid calling `new` and `delete` explicitly - **R.12**: Immediately give the result of an explicit resource allocation to a manager object - **R.13**: Perform at most one explicit resource allocation in a single expression statement - **R.20**: Use `unique_ptr` or `shared_ptr` to represent ownership - **R.21**: Prefer `unique_ptr` over `shared_ptr` unless you need to share ownership - **R.22**: Use `make_shared()` to make `shared_ptr`s - **R.23**: Use `make_unique()` to make `unique_ptr`s ## Error Handling - **E.1**: Develop an error-handling strategy early in a design - **E.2**: Throw an exception to signal that a function can't perform its assigned task - **E.3**: Use exceptions for error handling only - **E.6**: Use RAII to prevent leaks - **E.13**: Never throw while being the direct owner of an object - **E.14**: Use purpose-designed user-defined types as exceptions (not built-in types) - **E.16**: Destructors, deallocation, `swap`, and exception type copy/move construction must never fail - **E.17**: Don't try to catch every exception in every function - **E.18**: Minimize the use of explicit `try`/`catch` - **E.25**: If you can't throw exceptions, simulate RAII for resource management ## Performance (CRITICAL) **This is performance-critical software.** Apply these rules from [C++ Core Guidelines - Performance](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-performance): ### Core Performance Rules - **Per.1**: Don't optimize without reason - **Per.2**: Don't optimize prematurely - **Per.3**: Don't optimize something that's not performance critical - **Per.4**: Don't assume that complicated code is necessarily faster than simple code - **Per.5**: Don't assume that low-level code is necessarily faster than high-level code - **Per.6**: Don't make claims about performance without measurements - **Per.7**: Design to enable optimization - **Per.10**: Rely on the static type system - **Per.11**: Move computation from run time to compile time - **Per.19**: Access memory predictably (cache-friendly) ### Memory & Allocation ```cpp // 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 ``` ### Avoid Unnecessary Copies ```cpp // 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 } ``` ### Move Semantics ```cpp // 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; } }; ``` ### Cache-Friendly Code ```cpp // 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 ``` ### Compile-Time vs Runtime ```cpp // 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 ``` ### Avoid Performance Pitfalls | 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&` | ### Performance Checklist - [ ] No allocations in hot paths (pre-allocate, object pools) - [ ] Pass large objects by `const&`, small by value - [ ] Use `std::move` when transferring ownership - [ ] Containers sized with `reserve()` when size is known - [ ] Cache-friendly data access patterns - [ ] `constexpr` for compile-time computations - [ ] No unnecessary virtual calls in hot paths - [ ] Measured and profiled before micro-optimizing ## Testability (REQUIRED) **All C++ code must be designed for unit testing.** Use these patterns: ### Dependency Injection (Runtime) Inject dependencies through constructor or setter instead of creating them internally: ```cpp // 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 */ } }; ``` ### Policy-Based Design (Compile-time) Use templates with policy classes for compile-time dependency injection: ```cpp // 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
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る