internal/skills/content/cpp-guide/SKILL.md
C/C++ language guardrails, patterns, and best practices for AI-assisted development. Use when working with C/C++ files (.c, .cpp, .h, .hpp), CMakeLists.txt, or when the user mentions C/C++. Provides RAII patterns, smart pointer guidelines, move semantics, and testing standards specific to this project's coding standards.
npx skillsauth add ar4mirez/samuel cpp-guideInstall 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.
Applies to: C++20, Systems Programming, Embedded, Game Engines, High-Performance Computing
new/delete directly; use smart pointers and containers for all heap allocationconstexpr, static_assert, concepts, and templates to catch errors at compile time-Wall -Wextra -Wpedantic -Werror; every warning is a latent bug-std=c++20 / CMAKE_CXX_STANDARD 20)-Wall -Wextra -Wpedantic; treat warnings as errors (-Werror)-fsanitize=address,undefinedstatic_assert to verify assumptions about types, sizes, and alignmentsCMAKE_EXPORT_COMPILE_COMMANDS ON for clang-tidy and IDE integrationclang-format before every commit (no exceptions)clang-tidy with project checks before every commitsnake_case for functions, variables, namespaces, file namesPascalCase for types (classes, structs, enums, concepts, type aliases)SCREAMING_SNAKE_CASE for macros and compile-time constantsenum class over plain enum (scoped, no implicit conversion)#pragma once or traditional include guards consistently (pick one)using namespace std; in headers (allowed in .cpp function scope only)std::unique_ptr for single ownership (default smart pointer)std::shared_ptr only when ownership is genuinely shared; document whystd::make_unique and std::make_shared (exception-safe, single allocation)std::vector, std::string, std::array) manage their own memorystd::span for non-owning views into contiguous memorystd::string_view for non-owning string references (read-only, no allocation)std::optional<T> for values that may be absent (replaces sentinel values)std::variant<T, Error> or std::expected<T, E> (C++23) for result typesnoexcept when they do not throw (enables move optimization)const reference: catch (const std::exception& e)... without rethrowing or logging (swallowed errors are bugs)std::jthread over std::thread (automatic join, stop token support)std::mutex and std::scoped_lockstd::atomic for lock-free shared counters and flags-fsanitize=thread)std::latch, std::barrier, std::counting_semaphore (C++20) for coordinationmyproject/
├── CMakeLists.txt # Root: project(), options, add_subdirectory()
├── cmake/ # Shared CMake modules (warnings, sanitizers)
├── src/
│ ├── CMakeLists.txt # Library/executable targets
│ ├── main.cpp # Entry point (thin: parse args, call run)
│ ├── app.cpp / app.hpp
│ └── domain/
│ └── user.cpp / user.hpp
├── include/myproject/ # Public headers (for libraries)
├── tests/
│ ├── CMakeLists.txt # GoogleTest / Catch2 targets
│ └── test_user.cpp
├── benchmarks/
├── .clang-format
└── .clang-tidy
main.cpp should be thin: parse arguments, build config, call into library codeFetchContent or find_package for dependenciescmake_minimum_required(VERSION 3.20)
project(myproject VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_options(-Wall -Wextra -Wpedantic -Werror)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
add_link_options(-fsanitize=address,undefined)
endif()
add_subdirectory(src)
add_subdirectory(tests)
class FileHandle {
public:
explicit FileHandle(const std::filesystem::path& path)
: handle_(std::fopen(path.c_str(), "r")) {
if (!handle_) {
throw std::runtime_error("Failed to open: " + path.string());
}
}
~FileHandle() { if (handle_) std::fclose(handle_); }
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
FileHandle(FileHandle&& other) noexcept : handle_(std::exchange(other.handle_, nullptr)) {}
FileHandle& operator=(FileHandle&& other) noexcept {
if (this != &other) { if (handle_) std::fclose(handle_); handle_ = std::exchange(other.handle_, nullptr); }
return *this;
}
FILE* get() const noexcept { return handle_; }
private:
FILE* handle_;
};
// unique_ptr: default choice, single ownership
auto user = std::make_unique<User>("alice", "[email protected]");
process_user(*user); // pass by reference, not pointer
// shared_ptr: only when ownership is genuinely shared
auto config = std::make_shared<Config>(load_config("app.toml"));
auto worker1 = std::jthread([config] { serve(config); });
auto worker2 = std::jthread([config] { monitor(config); });
// weak_ptr: break reference cycles, optional observation
class TreeNode {
std::vector<std::shared_ptr<TreeNode>> children_;
std::weak_ptr<TreeNode> parent_; // non-owning back-reference
};
// Rule of Zero: prefer this. Let members manage resources.
struct UserRecord {
std::string name;
std::string email;
std::vector<std::string> roles;
// No special member functions needed -- std::string and std::vector handle everything.
};
// Rule of Five: only when managing a raw resource manually.
// See references/patterns.md for full RAII wrapper examples.
// Key rules: move constructors/assignment MUST be noexcept;
// use std::exchange to leave moved-from objects in a valid state.
// std::optional: replaces sentinel values (-1, nullptr, "")
std::optional<User> find_user(std::string_view email) {
auto it = users_.find(std::string(email));
if (it == users_.end()) return std::nullopt;
return it->second;
}
if (auto user = find_user("[email protected]")) {
std::println("Found: {}", user->name);
}
// std::variant: type-safe tagged union
using ParseResult = std::variant<int, double, std::string>;
std::visit(overloaded{
[](int v) { std::println("int: {}", v); },
[](double v) { std::println("double: {}", v); },
[](const std::string& v) { std::println("string: {}", v); },
}, result);
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
template<Hashable Key, typename Value>
class Cache {
public:
void put(const Key& key, Value value) { store_[key] = std::move(value); }
std::optional<Value> get(const Key& key) const {
auto it = store_.find(key);
return it != store_.end() ? std::optional(it->second) : std::nullopt;
}
private:
std::unordered_map<Key, Value> store_;
};
constexpr int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
consteval auto make_lookup_table() {
std::array<int, 256> table{};
for (int i = 0; i < 256; ++i) table[i] = (i * i) % 256;
return table;
}
constexpr auto kLookup = make_lookup_table();
auto active_user_emails(const std::vector<User>& users) {
return users
| std::views::filter([](const User& u) { return u.is_active; })
| std::views::transform(&User::email);
}
auto top_scores = scores
| std::views::filter([](int s) { return s > 0; })
| std::views::transform([](int s) { return s * 100 / max_score; })
| std::views::take(10);
for (const auto& [key, value] : config_map) {
std::println("{} = {}", key, value);
}
auto [min_it, max_it] = std::minmax_element(data.begin(), data.end());
auto [ok, msg, code] = process_request(req);
if (!ok) { log_error(msg, code); }
class UserServiceTest : public ::testing::Test {
protected:
void SetUp() override {
db_ = std::make_unique<InMemoryDatabase>();
service_ = std::make_unique<UserService>(*db_);
}
std::unique_ptr<InMemoryDatabase> db_;
std::unique_ptr<UserService> service_;
};
TEST_F(UserServiceTest, CreateUserSucceeds) {
auto user = service_->create_user("alice", "[email protected]");
EXPECT_EQ(user.name, "alice");
EXPECT_EQ(user.email, "[email protected]");
EXPECT_FALSE(user.id.empty());
}
TEST_F(UserServiceTest, DuplicateEmailThrows) {
service_->create_user("alice", "[email protected]");
EXPECT_THROW(service_->create_user("bob", "[email protected]"), DuplicateEmailError);
}
TEST_CASE("Parser handles valid input", "[parser]") {
Parser parser;
SECTION("integer literals") {
auto result = parser.parse("42");
REQUIRE(result.has_value());
CHECK(std::get<int>(*result) == 42);
}
SECTION("empty input returns nullopt") {
CHECK_FALSE(parser.parse("").has_value());
}
}
TEST(OrderService, CancelledOrderCannotBeShipped)TEST_F with fixtures for shared setup/teardownEXPECT_* for non-fatal assertions; ASSERT_* only when continuation is meaninglesscmake -B build -DCMAKE_BUILD_TYPE=Debug # Configure
cmake --build build -j$(nproc) # Build (parallel)
cmake --build build --target test # Run tests (CTest)
clang-format -i src/**/*.cpp src/**/*.hpp # Format
clang-tidy src/*.cpp -- -std=c++20 # Static analysis
gcovr --root . --html -o coverage.html # Coverage report
# .clang-format
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 100
PointerAlignment: Left
SortIncludes: CaseInsensitive
# .clang-tidy
Checks: >
-*, bugprone-*, cert-*, cppcoreguidelines-*, misc-*,
modernize-*, performance-*, readability-*,
-modernize-use-trailing-return-type
WarningsAsErrors: '*'
HeaderFilterRegex: 'src/.*'
| Sanitizer | Flag | Catches |
|-----------|------|---------|
| AddressSanitizer | -fsanitize=address | Buffer overflow, use-after-free, leaks |
| UndefinedBehaviorSanitizer | -fsanitize=undefined | Signed overflow, null deref, alignment |
| ThreadSanitizer | -fsanitize=thread | Data races, deadlocks |
| MemorySanitizer | -fsanitize=memory | Uninitialized reads (Clang only) |
-fno-omit-frame-pointer with sanitizersFor detailed patterns and examples, see:
development
Zig language guardrails, patterns, and best practices for AI-assisted development. Use when working with Zig files (.zig), build.zig, or when the user mentions Zig. Provides comptime patterns, allocator conventions, C interop guidelines, and testing standards specific to this project's coding standards.
tools
WordPress framework guardrails, patterns, and best practices for AI-assisted development. Use when working with WordPress projects, or when the user mentions WordPress. Provides theme development, plugin architecture, REST API, blocks, and security guidelines.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. Use when testing web apps, automating browser interactions, or debugging frontend issues.
tools
Suite of tools for creating elaborate, multi-component web applications using modern frontend technologies (React, Tailwind CSS, shadcn/ui). Use for complex projects requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX pages.