ChatGPT
Claude
Codex CLI
Cohere
Cursor
DeepSeek
Gemini
GitHub Copilot
GLM
Grok
Kimi
Llama
MiniMax
Mistral
OpenAI
opencode
Skill
cpp-pro
Write idiomatic C++ code with modern features, RAII, smart pointers, and STL algorithms. Handles templates, move semantics, and performance optimization.
Virus-scanned
Reviewed automatically before listing.
Download
sickn33-agentic-awesome-skills-skills_cpp-pro-286166a.zip · 16 KB
This skill couldn't be refreshed from GitHub on the last check — you're seeing the last imported snapshot.
Install
skills CLI
npx skills add https://github.com/sickn33/agentic-awesome-skills/tree/main/skills/cpp-pro
Claude Code
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install sickn33-agentic-awesome-skills@llmmart
Git
git clone https://github.com/sickn33/agentic-awesome-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole sickn33/agentic-awesome-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Use this skill when
- Working on cpp pro tasks or workflows
- Needing guidance, best practices, or checklists for cpp pro
Do not use this skill when
- The task is unrelated to cpp pro
- You need a different domain or tool outside this scope
Instructions
- Clarify goals, constraints, and required inputs.
- Apply relevant best practices and validate outcomes.
- Provide actionable steps and verification.
- If detailed examples are required, open
resources/implementation-playbook.md.
You are a C++ programming expert specializing in modern C++ and high-performance software.
Focus Areas
- Modern C++ (C++11/14/17/20/23) features
- RAII and smart pointers (unique_ptr, shared_ptr)
- Template metaprogramming and concepts
- Move semantics and perfect forwarding
- STL algorithms and containers
- Concurrency with std::thread and atomics
- Exception safety guarantees
Approach
- Prefer stack allocation and RAII over manual memory management
- Use smart pointers when heap allocation is necessary
- Follow the Rule of Zero/Three/Five
- Use const correctness and constexpr where applicable
- Leverage STL algorithms over raw loops
- Profile with tools like perf and VTune
Output
- Modern C++ code following best practices
- CMakeLists.txt with appropriate C++ standard
- Header files with proper include guards or #pragma once
- Unit tests using Google Test or Catch2
- AddressSanitizer/ThreadSanitizer clean output
- Performance benchmarks using Google Benchmark
- Clear documentation of template interfaces
Follow C++ Core Guidelines. Prefer compile-time errors over runtime errors.
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
Files (agentic-awesome-skills)
-
references
-
build-tooling.md 9.5 KB
# Build Systems and Tooling ## Modern CMake ```cmake cmake_minimum_required(VERSION 3.20) project(MyProject VERSION 1.0.0 LANGUAGES CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Export compile commands for tools set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Compiler warnings if(MSVC) add_compile_options(/W4 /WX) else() add_compile_options(-Wall -Wextra -Wpedantic -Werror) endif() # Create library target add_library(mylib src/mylib.cpp include/mylib.h ) target_include_directories(mylib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_compile_features(mylib PUBLIC cxx_std_20) # Create executable add_executable(myapp src/main.cpp) target_link_libraries(myapp PRIVATE mylib) # Dependencies with FetchContent include(FetchContent) FetchContent_Declare( fmt GIT_REPOSITORY https://github.com/fmtlib/fmt.git GIT_TAG 10.1.1 ) FetchContent_MakeAvailable(fmt) target_link_libraries(mylib PUBLIC fmt::fmt) # Testing enable_testing() add_subdirectory(tests) # Install rules include(GNUInstallDirs) install(TARGETS mylib myapp EXPORT MyProjectTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) ``` ## Sanitizers ```cmake # AddressSanitizer (ASan) - memory errors set(CMAKE_CXX_FLAGS_ASAN "-g -O1 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags for ASan build" ) # UndefinedBehaviorSanitizer (UBSan) set(CMAKE_CXX_FLAGS_UBSAN "-g -O1 -fsanitize=undefined -fno-omit-frame-pointer" CACHE STRING "Flags for UBSan build" ) # ThreadSanitizer (TSan) - data races set(CMAKE_CXX_FLAGS_TSAN "-g -O1 -fsanitize=thread -fno-omit-frame-pointer" CACHE STRING "Flags for TSan build" ) # MemorySanitizer (MSan) - uninitialized reads set(CMAKE_CXX_FLAGS_MSAN "-g -O1 -fsanitize=memory -fno-omit-frame-pointer" CACHE STRING "Flags for MSan build" ) # Usage: cmake -DCMAKE_BUILD_TYPE=ASAN .. ``` ## Static Analysis ```yaml # .clang-tidy configuration --- Checks: > *, -fuchsia-*, -google-*, -llvm-*, -modernize-use-trailing-return-type, -readability-identifier-length WarningsAsErrors: '*' CheckOptions: - key: readability-identifier-naming.ClassCase value: CamelCase - key: readability-identifier-naming.FunctionCase value: lower_case - key: readability-identifier-naming.VariableCase value: lower_case - key: readability-identifier-naming.ConstantCase value: UPPER_CASE - key: readability-identifier-naming.MemberCase value: lower_case - key: readability-identifier-naming.MemberSuffix value: '_' - key: modernize-use-nullptr.NullMacros value: 'NULL' ``` ```bash # Run clang-tidy clang-tidy src/*.cpp -p build/ # Run cppcheck cppcheck --enable=all --std=c++20 --suppress=missingInclude src/ # Run include-what-you-use include-what-you-use -std=c++20 src/main.cpp ``` ## Testing with Catch2 ```cpp #include <catch2/catch_test_macros.hpp> #include <catch2/benchmark/catch_benchmark.hpp> #include "mylib.h" TEST_CASE("Vector operations", "[vector]") { std::vector<int> vec{1, 2, 3}; SECTION("push_back") { vec.push_back(4); REQUIRE(vec.size() == 4); REQUIRE(vec.back() == 4); } SECTION("pop_back") { vec.pop_back(); REQUIRE(vec.size() == 2); REQUIRE(vec.back() == 2); } } TEST_CASE("Exception handling", "[exceptions]") { REQUIRE_THROWS_AS(risky_function(), std::runtime_error); REQUIRE_THROWS_WITH(risky_function(), "error message"); } TEST_CASE("Floating point", "[math]") { REQUIRE_THAT(compute_value(), Catch::Matchers::WithinAbs(3.14, 0.01)); } BENCHMARK("Vector creation") { return std::vector<int>(1000); }; BENCHMARK("Vector fill") { std::vector<int> vec(1000); for (int i = 0; i < 1000; ++i) { vec[i] = i; } return vec; }; ``` ## Testing with GoogleTest ```cpp #include <gtest/gtest.h> #include <gmock/gmock.h> #include "calculator.h" class CalculatorTest : public ::testing::Test { protected: void SetUp() override { calc = std::make_unique<Calculator>(); } void TearDown() override { calc.reset(); } std::unique_ptr<Calculator> calc; }; TEST_F(CalculatorTest, Addition) { EXPECT_EQ(calc->add(2, 3), 5); EXPECT_EQ(calc->add(-1, 1), 0); } TEST_F(CalculatorTest, Division) { EXPECT_DOUBLE_EQ(calc->divide(10, 2), 5.0); EXPECT_THROW(calc->divide(10, 0), std::invalid_argument); } // Parameterized tests class AdditionTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {}; TEST_P(AdditionTest, ValidAddition) { auto [a, b, expected] = GetParam(); Calculator calc; EXPECT_EQ(calc.add(a, b), expected); } INSTANTIATE_TEST_SUITE_P( AdditionSuite, AdditionTest, ::testing::Values( std::make_tuple(1, 2, 3), std::make_tuple(-1, -2, -3), std::make_tuple(0, 0, 0) ) ); // Mock objects class MockDatabase : public Database { public: MOCK_METHOD(void, connect, (const std::string&), (override)); MOCK_METHOD(std::string, query, (const std::string&), (override)); MOCK_METHOD(void, disconnect, (), (override)); }; TEST(ServiceTest, UsesDatabase) { MockDatabase mock_db; EXPECT_CALL(mock_db, connect("localhost")) .Times(1); EXPECT_CALL(mock_db, query("SELECT *")) .WillOnce(::testing::Return("result")); Service service(mock_db); service.process(); } ``` ## Performance Profiling ```cpp // Benchmark with Google Benchmark #include <benchmark/benchmark.h> static void BM_VectorPush(benchmark::State& state) { for (auto _ : state) { std::vector<int> vec; for (int i = 0; i < state.range(0); ++i) { vec.push_back(i); } benchmark::DoNotOptimize(vec); } } BENCHMARK(BM_VectorPush)->Range(8, 8<<10); static void BM_VectorReserve(benchmark::State& state) { for (auto _ : state) { std::vector<int> vec; vec.reserve(state.range(0)); for (int i = 0; i < state.range(0); ++i) { vec.push_back(i); } benchmark::DoNotOptimize(vec); } } BENCHMARK(BM_VectorReserve)->Range(8, 8<<10); BENCHMARK_MAIN(); ``` ```bash # Profiling with perf (Linux) perf record -g ./myapp perf report # Profiling with Instruments (macOS) instruments -t "Time Profiler" ./myapp # Valgrind callgrind valgrind --tool=callgrind ./myapp kcachegrind callgrind.out.* # Memory profiling valgrind --tool=massif ./myapp ms_print massif.out.* ``` ## Conan Package Manager ```python # conanfile.txt [requires] fmt/10.1.1 spdlog/1.12.0 catch2/3.4.0 [generators] CMakeDeps CMakeToolchain [options] fmt:header_only=True ``` ```cmake # CMakeLists.txt with Conan cmake_minimum_required(VERSION 3.20) project(MyProject) find_package(fmt REQUIRED) find_package(spdlog REQUIRED) find_package(Catch2 REQUIRED) add_executable(myapp src/main.cpp) target_link_libraries(myapp PRIVATE fmt::fmt spdlog::spdlog ) add_executable(tests test/main.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain ) ``` ```bash # Install dependencies conan install . --output-folder=build --build=missing cd build cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake cmake --build . ``` ## CI/CD with GitHub Actions ```yaml # .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] compiler: [gcc, clang, msvc] build_type: [Debug, Release] steps: - uses: actions/checkout@v3 - name: Install dependencies run: | pip install conan conan install . --output-folder=build --build=missing - name: Configure run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - name: Build run: cmake --build build --config ${{ matrix.build_type }} - name: Test run: ctest --test-dir build -C ${{ matrix.build_type }} sanitizers: runs-on: ubuntu-latest strategy: matrix: sanitizer: [asan, ubsan, tsan] steps: - uses: actions/checkout@v3 - name: Build with sanitizer run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.sanitizer }} cmake --build build - name: Run tests run: ctest --test-dir build static-analysis: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run clang-tidy run: | cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON clang-tidy src/*.cpp -p build/ - name: Run cppcheck run: cppcheck --enable=all --error-exitcode=1 src/ ``` ## Quick Reference | Tool | Purpose | Command | |------|---------|---------| | CMake | Build system | `cmake -B build && cmake --build build` | | Conan | Package manager | `conan install . --build=missing` | | ASan | Memory errors | `-fsanitize=address` | | UBSan | Undefined behavior | `-fsanitize=undefined` | | TSan | Data races | `-fsanitize=thread` | | clang-tidy | Static analysis | `clang-tidy src/*.cpp` | | cppcheck | Static analysis | `cppcheck --enable=all src/` | | Catch2 | Unit testing | `TEST_CASE("name") { REQUIRE(...); }` | | GoogleTest | Unit testing | `TEST(Suite, Name) { EXPECT_EQ(...); }` | | Google Benchmark | Performance | `BENCHMARK(func)->Range(...)` | | Valgrind | Memory profiler | `valgrind --tool=memcheck ./app` | -
concurrency.md 10.7 KB
# Concurrency and Parallel Programming ## Atomics and Memory Ordering ```cpp #include <atomic> #include <thread> // Basic atomics std::atomic<int> counter{0}; std::atomic<bool> flag{false}; // Memory ordering void producer(std::atomic<int>& data, std::atomic<bool>& ready) { data.store(42, std::memory_order_relaxed); ready.store(true, std::memory_order_release); // Release barrier } void consumer(std::atomic<int>& data, std::atomic<bool>& ready) { while (!ready.load(std::memory_order_acquire)) { // Acquire barrier std::this_thread::yield(); } int value = data.load(std::memory_order_relaxed); } // Compare-and-swap bool try_acquire_lock(std::atomic<bool>& lock) { bool expected = false; return lock.compare_exchange_strong(expected, true, std::memory_order_acquire, std::memory_order_relaxed); } // Fetch-and-add int increment_counter(std::atomic<int>& counter) { return counter.fetch_add(1, std::memory_order_relaxed); } ``` ## Lock-Free Data Structures ```cpp #include <atomic> #include <memory> // Lock-free stack template<typename T> class LockFreeStack { struct Node { T data; Node* next; Node(const T& value) : data(value), next(nullptr) {} }; std::atomic<Node*> head_{nullptr}; public: void push(const T& value) { Node* new_node = new Node(value); new_node->next = head_.load(std::memory_order_relaxed); while (!head_.compare_exchange_weak(new_node->next, new_node, std::memory_order_release, std::memory_order_relaxed)) { // Retry with updated head } } bool pop(T& result) { Node* old_head = head_.load(std::memory_order_relaxed); while (old_head && !head_.compare_exchange_weak(old_head, old_head->next, std::memory_order_acquire, std::memory_order_relaxed)) { // Retry } if (old_head) { result = old_head->data; delete old_head; // Note: ABA problem exists return true; } return false; } }; // Lock-free queue (single producer, single consumer) template<typename T, size_t Size> class SPSCQueue { std::array<T, Size> buffer_; alignas(64) std::atomic<size_t> head_{0}; alignas(64) std::atomic<size_t> tail_{0}; public: bool push(const T& item) { size_t head = head_.load(std::memory_order_relaxed); size_t next_head = (head + 1) % Size; if (next_head == tail_.load(std::memory_order_acquire)) { return false; // Queue full } buffer_[head] = item; head_.store(next_head, std::memory_order_release); return true; } bool pop(T& item) { size_t tail = tail_.load(std::memory_order_relaxed); if (tail == head_.load(std::memory_order_acquire)) { return false; // Queue empty } item = buffer_[tail]; tail_.store((tail + 1) % Size, std::memory_order_release); return true; } }; ``` ## Thread Pool ```cpp #include <thread> #include <queue> #include <mutex> #include <condition_variable> #include <functional> #include <future> class ThreadPool { std::vector<std::thread> workers_; std::queue<std::function<void()>> tasks_; std::mutex queue_mutex_; std::condition_variable condition_; bool stop_ = false; public: ThreadPool(size_t num_threads) { for (size_t i = 0; i < num_threads; ++i) { workers_.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(queue_mutex_); condition_.wait(lock, [this] { return stop_ || !tasks_.empty(); }); if (stop_ && tasks_.empty()) { return; } task = std::move(tasks_.front()); tasks_.pop(); } task(); } }); } } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queue_mutex_); stop_ = true; } condition_.notify_all(); for (auto& worker : workers_) { worker.join(); } } template<typename F, typename... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::invoke_result_t<F, Args...>> { using return_type = typename std::invoke_result_t<F, Args...>; auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> result = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex_); if (stop_) { throw std::runtime_error("enqueue on stopped ThreadPool"); } tasks_.emplace([task]() { (*task)(); }); } condition_.notify_one(); return result; } }; ``` ## Parallel STL Algorithms ```cpp #include <algorithm> #include <execution> #include <vector> #include <numeric> void parallel_algorithms_demo() { std::vector<int> vec(1'000'000); std::iota(vec.begin(), vec.end(), 0); // Parallel sort std::sort(std::execution::par, vec.begin(), vec.end()); // Parallel for_each std::for_each(std::execution::par_unseq, vec.begin(), vec.end(), [](int& x) { x *= 2; }); // Parallel transform std::vector<int> result(vec.size()); std::transform(std::execution::par, vec.begin(), vec.end(), result.begin(), [](int x) { return x * x; }); // Parallel reduce int sum = std::reduce(std::execution::par, vec.begin(), vec.end()); // Parallel transform_reduce (map-reduce) int sum_of_squares = std::transform_reduce( std::execution::par, vec.begin(), vec.end(), 0, std::plus<>(), [](int x) { return x * x; } ); } ``` ## Synchronization Primitives ```cpp #include <mutex> #include <shared_mutex> #include <condition_variable> // Mutex types std::mutex mtx; std::recursive_mutex rec_mtx; std::timed_mutex timed_mtx; std::shared_mutex shared_mtx; // RAII locks void exclusive_access() { std::lock_guard<std::mutex> lock(mtx); // Critical section } void unique_lock_example() { std::unique_lock<std::mutex> lock(mtx); // Can unlock and relock lock.unlock(); // Do some work lock.lock(); } // Reader-writer lock class SharedData { mutable std::shared_mutex mutex_; std::string data_; public: std::string read() const { std::shared_lock<std::shared_mutex> lock(mutex_); return data_; } void write(std::string new_data) { std::unique_lock<std::shared_mutex> lock(mutex_); data_ = std::move(new_data); } }; // Condition variable class Queue { std::queue<int> queue_; std::mutex mutex_; std::condition_variable cv_; public: void push(int value) { { std::lock_guard<std::mutex> lock(mutex_); queue_.push(value); } cv_.notify_one(); } int pop() { std::unique_lock<std::mutex> lock(mutex_); cv_.wait(lock, [this] { return !queue_.empty(); }); int value = queue_.front(); queue_.pop(); return value; } }; // std::scoped_lock - multiple mutexes std::mutex mtx1, mtx2; void transfer(Account& from, Account& to, int amount) { std::scoped_lock lock(from.mutex, to.mutex); // Deadlock-free from.balance -= amount; to.balance += amount; } ``` ## Async and Futures ```cpp #include <future> // std::async auto future = std::async(std::launch::async, []() { return expensive_computation(); }); // Get result (blocks until ready) auto result = future.get(); // Promise and future void producer(std::promise<int> promise) { int value = compute_value(); promise.set_value(value); } void consumer(std::future<int> future) { int value = future.get(); } std::promise<int> promise; std::future<int> future = promise.get_future(); std::thread producer_thread(producer, std::move(promise)); std::thread consumer_thread(consumer, std::move(future)); // Packaged task std::packaged_task<int(int, int)> task([](int a, int b) { return a + b; }); std::future<int> task_future = task.get_future(); std::thread task_thread(std::move(task), 5, 3); int sum = task_future.get(); // 8 task_thread.join(); ``` ## Coroutine-Based Concurrency ```cpp #include <coroutine> #include <optional> // Async task coroutine template<typename T> struct AsyncTask { struct promise_type { std::optional<T> value; std::exception_ptr exception; AsyncTask get_return_object() { return AsyncTask{ std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_never initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T v) { value = std::move(v); } void unhandled_exception() { exception = std::current_exception(); } }; std::coroutine_handle<promise_type> handle; AsyncTask(std::coroutine_handle<promise_type> h) : handle(h) {} ~AsyncTask() { if (handle) handle.destroy(); } T get() { if (!handle.done()) { handle.resume(); } if (handle.promise().exception) { std::rethrow_exception(handle.promise().exception); } return *handle.promise().value; } }; // Usage AsyncTask<int> async_compute() { co_return 42; } ``` ## Quick Reference | Primitive | Use Case | Performance | |-----------|----------|-------------| | std::atomic | Simple shared state | Lock-free | | std::mutex | Exclusive access | Kernel call | | std::shared_mutex | Read-heavy workload | Better than mutex | | Lock-free structures | High contention | Best throughput | | Thread pool | Task parallelism | Avoid thread overhead | | Parallel STL | Data parallelism | Automatic scaling | | std::async | Simple async tasks | Thread pool | | Coroutines | Async I/O | Minimal overhead | ## Memory Ordering Guide | Ordering | Guarantees | Use Case | |----------|-----------|----------| | relaxed | No synchronization | Counters | | acquire | Load barrier | Consumer | | release | Store barrier | Producer | | acq_rel | Both | RMW operations | | seq_cst | Total order | Default | -
memory-performance.md 8.9 KB
# Memory Management & Performance ## Smart Pointers ```cpp #include <memory> // unique_ptr - exclusive ownership auto create_resource() { return std::make_unique<Resource>("data"); } // shared_ptr - reference counting std::shared_ptr<Data> shared = std::make_shared<Data>(42); std::weak_ptr<Data> weak = shared; // Non-owning reference // Custom deleters auto file_deleter = [](FILE* fp) { if (fp) fclose(fp); }; std::unique_ptr<FILE, decltype(file_deleter)> file( fopen("data.txt", "r"), file_deleter ); // enable_shared_from_this class Node : public std::enable_shared_from_this<Node> { public: std::shared_ptr<Node> get_shared() { return shared_from_this(); } }; ``` ## Custom Allocators ```cpp #include <memory> #include <vector> // Pool allocator for fixed-size objects template<typename T, size_t PoolSize = 1024> class PoolAllocator { struct Block { alignas(T) std::byte data[sizeof(T)]; Block* next; }; Block pool_[PoolSize]; Block* free_list_ = nullptr; public: using value_type = T; PoolAllocator() { // Initialize free list for (size_t i = 0; i < PoolSize - 1; ++i) { pool_[i].next = &pool_[i + 1]; } pool_[PoolSize - 1].next = nullptr; free_list_ = &pool_[0]; } T* allocate(size_t n) { if (n != 1 || !free_list_) { throw std::bad_alloc(); } Block* block = free_list_; free_list_ = free_list_->next; return reinterpret_cast<T*>(block->data); } void deallocate(T* p, size_t n) { if (n != 1) return; Block* block = reinterpret_cast<Block*>(p); block->next = free_list_; free_list_ = block; } }; // Usage std::vector<int, PoolAllocator<int>> vec; // Arena allocator - bump allocator class Arena { std::byte* buffer_; size_t size_; size_t offset_ = 0; public: Arena(size_t size) : size_(size) { buffer_ = new std::byte[size]; } ~Arena() { delete[] buffer_; } template<typename T> T* allocate(size_t n = 1) { size_t alignment = alignof(T); size_t space = size_ - offset_; void* ptr = buffer_ + offset_; if (std::align(alignment, sizeof(T) * n, ptr, space)) { offset_ = size_ - space + sizeof(T) * n; return static_cast<T*>(ptr); } throw std::bad_alloc(); } void reset() { offset_ = 0; } }; ``` ## Move Semantics ```cpp #include <utility> #include <algorithm> class Buffer { size_t size_; char* data_; public: // Constructor Buffer(size_t size) : size_(size), data_(new char[size]) {} // Destructor ~Buffer() { delete[] data_; } // Copy constructor Buffer(const Buffer& other) : size_(other.size_), data_(new char[size_]) { std::copy(other.data_, other.data_ + size_, data_); } // Copy assignment Buffer& operator=(const Buffer& other) { if (this != &other) { delete[] data_; size_ = other.size_; data_ = new char[size_]; std::copy(other.data_, other.data_ + size_, data_); } return *this; } // Move constructor Buffer(Buffer&& other) noexcept : size_(other.size_), data_(other.data_) { other.size_ = 0; other.data_ = nullptr; } // Move assignment Buffer& operator=(Buffer&& other) noexcept { if (this != &other) { delete[] data_; size_ = other.size_; data_ = other.data_; other.size_ = 0; other.data_ = nullptr; } return *this; } }; // Perfect forwarding template<typename T> void wrapper(T&& arg) { process(std::forward<T>(arg)); // Preserves lvalue/rvalue } ``` ## SIMD Optimization ```cpp #include <immintrin.h> // AVX/AVX2 #include <cstring> // Vectorized sum using AVX2 float simd_sum(const float* data, size_t size) { __m256 sum_vec = _mm256_setzero_ps(); size_t i = 0; // Process 8 floats at a time for (; i + 8 <= size; i += 8) { __m256 vec = _mm256_loadu_ps(&data[i]); sum_vec = _mm256_add_ps(sum_vec, vec); } // Horizontal sum alignas(32) float temp[8]; _mm256_store_ps(temp, sum_vec); float result = 0.0f; for (int j = 0; j < 8; ++j) { result += temp[j]; } // Handle remaining elements for (; i < size; ++i) { result += data[i]; } return result; } // Vectorized multiply-add void fma_operation(float* result, const float* a, const float* b, const float* c, size_t size) { for (size_t i = 0; i + 8 <= size; i += 8) { __m256 va = _mm256_loadu_ps(&a[i]); __m256 vb = _mm256_loadu_ps(&b[i]); __m256 vc = _mm256_loadu_ps(&c[i]); // result[i] = a[i] * b[i] + c[i] __m256 vr = _mm256_fmadd_ps(va, vb, vc); _mm256_storeu_ps(&result[i], vr); } } ``` ## Cache-Friendly Design ```cpp // Structure of Arrays (SoA) - better cache locality struct ParticlesAoS { struct Particle { float x, y, z; float vx, vy, vz; }; std::vector<Particle> particles; }; struct ParticlesSoA { std::vector<float> x, y, z; std::vector<float> vx, vy, vz; void update_positions(float dt) { // All x coordinates are contiguous - better cache usage for (size_t i = 0; i < x.size(); ++i) { x[i] += vx[i] * dt; y[i] += vy[i] * dt; z[i] += vz[i] * dt; } } }; // Cache line padding to avoid false sharing struct alignas(64) CacheLinePadded { std::atomic<int> counter; char padding[64 - sizeof(std::atomic<int>)]; }; // Prefetching void process_with_prefetch(const int* data, size_t size) { for (size_t i = 0; i < size; ++i) { // Prefetch data for next iteration if (i + 8 < size) { __builtin_prefetch(&data[i + 8], 0, 1); } // Process current data process(data[i]); } } ``` ## Memory Pool ```cpp #include <vector> #include <memory> template<typename T, size_t ChunkSize = 256> class MemoryPool { struct Chunk { alignas(T) std::byte data[sizeof(T) * ChunkSize]; }; std::vector<std::unique_ptr<Chunk>> chunks_; std::vector<T*> free_list_; size_t current_chunk_offset_ = ChunkSize; public: T* allocate() { if (!free_list_.empty()) { T* ptr = free_list_.back(); free_list_.pop_back(); return ptr; } if (current_chunk_offset_ >= ChunkSize) { chunks_.push_back(std::make_unique<Chunk>()); current_chunk_offset_ = 0; } Chunk* chunk = chunks_.back().get(); T* ptr = reinterpret_cast<T*>( &chunk->data[sizeof(T) * current_chunk_offset_++] ); return ptr; } void deallocate(T* ptr) { free_list_.push_back(ptr); } template<typename... Args> T* construct(Args&&... args) { T* ptr = allocate(); new (ptr) T(std::forward<Args>(args)...); return ptr; } void destroy(T* ptr) { ptr->~T(); deallocate(ptr); } }; ``` ## Copy Elision and RVO ```cpp // Return Value Optimization (RVO) std::vector<int> create_vector() { std::vector<int> vec{1, 2, 3, 4, 5}; return vec; // RVO applies, no copy/move } // Named Return Value Optimization (NRVO) std::string build_string(bool condition) { std::string result; if (condition) { result = "condition true"; } else { result = "condition false"; } return result; // NRVO may apply } // Guaranteed copy elision (C++17) struct NonMovable { NonMovable() = default; NonMovable(const NonMovable&) = delete; NonMovable(NonMovable&&) = delete; }; NonMovable create() { return NonMovable{}; // Guaranteed no copy/move in C++17 } auto obj = create(); // OK in C++17 ``` ## Alignment and Memory Layout ```cpp #include <cstddef> // Control alignment struct alignas(64) CacheAligned { int data[16]; }; // Check alignment static_assert(alignof(CacheAligned) == 64); // Aligned allocation void* aligned_alloc_wrapper(size_t alignment, size_t size) { void* ptr = nullptr; if (posix_memalign(&ptr, alignment, size) != 0) { throw std::bad_alloc(); } return ptr; } // Placement new with alignment alignas(32) std::byte buffer[sizeof(Data)]; Data* obj = new (buffer) Data(); obj->~Data(); // Manual destruction needed ``` ## Quick Reference | Technique | Use Case | Benefit | |-----------|----------|---------| | Smart Pointers | Ownership management | Memory safety | | Move Semantics | Avoid copies | Performance | | Custom Allocators | Specialized allocation | Speed + control | | SIMD | Parallel computation | 4-8x speedup | | SoA Layout | Sequential access | Cache efficiency | | Memory Pools | Frequent alloc/dealloc | Reduced fragmentation | | Alignment | SIMD/cache optimization | Performance | | RVO/NRVO | Return objects | Zero-copy | -
modern-cpp.md 6.4 KB
# Modern C++20/23 Features ## Concepts and Constraints ```cpp #include <concepts> // Define custom concepts template<typename T> concept Numeric = std::integral<T> || std::floating_point<T>; template<typename T> concept Hashable = requires(T a) { { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>; }; template<typename T> concept Container = requires(T c) { typename T::value_type; typename T::iterator; { c.begin() } -> std::same_as<typename T::iterator>; { c.end() } -> std::same_as<typename T::iterator>; { c.size() } -> std::convertible_to<std::size_t>; }; // Use concepts for function constraints template<Numeric T> T add(T a, T b) { return a + b; } // Concept-based overloading template<std::integral T> void process(T value) { std::cout << "Processing integer: " << value << '\n'; } template<std::floating_point T> void process(T value) { std::cout << "Processing float: " << value << '\n'; } ``` ## Ranges and Views ```cpp #include <ranges> #include <vector> #include <algorithm> // Ranges-based algorithms std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Filter, transform, take - all lazy evaluation auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; }) | std::views::take(3); // Copy to vector only when needed std::vector<int> materialized(result.begin(), result.end()); // Custom range adaptor auto is_even = [](int n) { return n % 2 == 0; }; auto square = [](int n) { return n * n; }; auto pipeline = std::views::filter(is_even) | std::views::transform(square); auto processed = numbers | pipeline; ``` ## Coroutines ```cpp #include <coroutine> #include <iostream> #include <memory> // Generator coroutine template<typename T> struct Generator { struct promise_type { T current_value; auto get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(T value) { current_value = value; return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; std::coroutine_handle<promise_type> handle; Generator(std::coroutine_handle<promise_type> h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } bool move_next() { handle.resume(); return !handle.done(); } T current_value() { return handle.promise().current_value; } }; // Usage Generator<int> fibonacci() { int a = 0, b = 1; while (true) { co_yield a; auto next = a + b; a = b; b = next; } } // Async coroutine #include <future> struct Task { struct promise_type { Task get_return_object() { return Task{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} }; std::coroutine_handle<promise_type> handle; }; Task async_operation() { std::cout << "Starting async work\n"; co_await std::suspend_always{}; std::cout << "Resuming async work\n"; } ``` ## Three-Way Comparison (Spaceship) ```cpp #include <compare> struct Point { int x, y; // Auto-generate all comparison operators auto operator<=>(const Point&) const = default; }; // Custom spaceship operator struct Version { int major, minor, patch; std::strong_ordering operator<=>(const Version& other) const { if (auto cmp = major <=> other.major; cmp != 0) return cmp; if (auto cmp = minor <=> other.minor; cmp != 0) return cmp; return patch <=> other.patch; } bool operator==(const Version& other) const = default; }; ``` ## Designated Initializers ```cpp struct Config { std::string host = "localhost"; int port = 8080; bool ssl_enabled = false; int timeout_ms = 5000; }; // C++20 designated initializers Config cfg { .host = "example.com", .port = 443, .ssl_enabled = true // timeout_ms uses default }; ``` ## Modules (C++20) ```cpp // math.cppm - module interface export module math; export namespace math { template<typename T> T add(T a, T b) { return a + b; } class Calculator { public: int multiply(int a, int b); }; } // Implementation module math; int math::Calculator::multiply(int a, int b) { return a * b; } // Usage in other files import math; int main() { auto result = math::add(5, 3); math::Calculator calc; auto product = calc.multiply(4, 7); } ``` ## constexpr Enhancements ```cpp #include <string> #include <vector> #include <algorithm> // C++20: constexpr std::string and std::vector constexpr auto compute_at_compile_time() { std::vector<int> vec{1, 2, 3, 4, 5}; std::ranges::reverse(vec); return vec[0]; // Returns 5 } constexpr int value = compute_at_compile_time(); // constexpr virtual functions (C++20) struct Base { constexpr virtual int get_value() const { return 42; } constexpr virtual ~Base() = default; }; struct Derived : Base { constexpr int get_value() const override { return 100; } }; ``` ## std::format (C++20) ```cpp #include <format> #include <iostream> int main() { std::string msg = std::format("Hello, {}!", "World"); // Positional arguments auto text = std::format("{1} {0}", "World", "Hello"); // Formatting options double pi = 3.14159265; auto formatted = std::format("Pi: {:.2f}", pi); // "Pi: 3.14" // Custom types struct Point { int x, y; }; } // Custom formatter template<> struct std::formatter<Point> { constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } auto format(const Point& p, format_context& ctx) const { return std::format_to(ctx.out(), "({}, {})", p.x, p.y); } }; ``` ## Quick Reference | Feature | C++17 | C++20 | C++23 | |---------|-------|-------|-------| | Concepts | - | ✓ | ✓ | | Ranges | - | ✓ | ✓ | | Coroutines | - | ✓ | ✓ | | Modules | - | ✓ | ✓ | | Spaceship | - | ✓ | ✓ | | std::format | - | ✓ | ✓ | | std::expected | - | - | ✓ | | std::print | - | - | ✓ | | Deducing this | - | - | ✓ | -
templates.md 7.7 KB
# Template Metaprogramming ## Variadic Templates ```cpp #include <iostream> #include <utility> // Fold expressions (C++17) template<typename... Args> auto sum(Args... args) { return (args + ...); // Unary right fold } template<typename... Args> void print(Args&&... args) { ((std::cout << args << ' '), ...); // Binary left fold std::cout << '\n'; } // Recursive variadic template template<typename T> void log(T&& value) { std::cout << value << '\n'; } template<typename T, typename... Args> void log(T&& first, Args&&... rest) { std::cout << first << ", "; log(std::forward<Args>(rest)...); } // Parameter pack expansion template<typename... Types> struct TypeList { static constexpr size_t size = sizeof...(Types); }; template<typename... Args> auto make_tuple_advanced(Args&&... args) { return std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...); } ``` ## SFINAE and if constexpr ```cpp #include <type_traits> // SFINAE with std::enable_if (older style) template<typename T> std::enable_if_t<std::is_integral_v<T>, T> double_value(T value) { return value * 2; } template<typename T> std::enable_if_t<std::is_floating_point_v<T>, T> double_value(T value) { return value * 2.0; } // Modern: if constexpr (C++17) template<typename T> auto process(T value) { if constexpr (std::is_integral_v<T>) { return value * 2; } else if constexpr (std::is_floating_point_v<T>) { return value * 2.0; } else { return value; } } // Detection idiom template<typename T, typename = void> struct has_serialize : std::false_type {}; template<typename T> struct has_serialize<T, std::void_t<decltype(std::declval<T>().serialize())>> : std::true_type {}; template<typename T> constexpr bool has_serialize_v = has_serialize<T>::value; // Use with if constexpr template<typename T> void save(const T& obj) { if constexpr (has_serialize_v<T>) { obj.serialize(); } else { // Default serialization } } ``` ## Type Traits ```cpp #include <type_traits> // Custom type traits template<typename T> struct remove_all_pointers { using type = T; }; template<typename T> struct remove_all_pointers<T*> { using type = typename remove_all_pointers<T>::type; }; template<typename T> using remove_all_pointers_t = typename remove_all_pointers<T>::type; // Conditional types template<bool Condition, typename T, typename F> struct conditional_type { using type = T; }; template<typename T, typename F> struct conditional_type<false, T, F> { using type = F; }; // Compile-time type selection template<size_t N> struct best_integral_type { using type = std::conditional_t<N <= 8, uint8_t, std::conditional_t<N <= 16, uint16_t, std::conditional_t<N <= 32, uint32_t, uint64_t>>>; }; // Check for member functions template<typename T, typename = void> struct has_reserve : std::false_type {}; template<typename T> struct has_reserve<T, std::void_t<decltype(std::declval<T>().reserve(size_t{}))>> : std::true_type {}; ``` ## CRTP (Curiously Recurring Template Pattern) ```cpp // Static polymorphism with CRTP template<typename Derived> class Shape { public: double area() const { return static_cast<const Derived*>(this)->area_impl(); } void draw() const { static_cast<const Derived*>(this)->draw_impl(); } }; class Circle : public Shape<Circle> { double radius_; public: Circle(double r) : radius_(r) {} double area_impl() const { return 3.14159 * radius_ * radius_; } void draw_impl() const { std::cout << "Drawing circle\n"; } }; class Rectangle : public Shape<Rectangle> { double width_, height_; public: Rectangle(double w, double h) : width_(w), height_(h) {} double area_impl() const { return width_ * height_; } void draw_impl() const { std::cout << "Drawing rectangle\n"; } }; // CRTP for mixin capabilities template<typename Derived> class Printable { public: void print() const { std::cout << static_cast<const Derived*>(this)->to_string() << '\n'; } }; class User : public Printable<User> { std::string name_; public: User(std::string name) : name_(std::move(name)) {} std::string to_string() const { return "User: " + name_; } }; ``` ## Template Template Parameters ```cpp #include <vector> #include <list> #include <deque> // Template template parameter template<typename T, template<typename, typename> class Container> class Stack { Container<T, std::allocator<T>> data_; public: void push(const T& value) { data_.push_back(value); } T pop() { T value = data_.back(); data_.pop_back(); return value; } size_t size() const { return data_.size(); } }; // Usage with different containers Stack<int, std::vector> vector_stack; Stack<int, std::deque> deque_stack; Stack<int, std::list> list_stack; ``` ## Compile-Time Computation ```cpp #include <array> // Compile-time factorial constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); } constexpr int fact_5 = factorial(5); // Computed at compile time // Compile-time prime checking constexpr bool is_prime(int n) { if (n < 2) return false; for (int i = 2; i * i <= n; ++i) { if (n % i == 0) return false; } return true; } // Generate compile-time array of primes template<size_t N> constexpr auto generate_primes() { std::array<int, N> primes{}; int count = 0; int candidate = 2; while (count < N) { if (is_prime(candidate)) { primes[count++] = candidate; } ++candidate; } return primes; } constexpr auto first_10_primes = generate_primes<10>(); ``` ## Expression Templates ```cpp // Lazy evaluation with expression templates template<typename E> class VecExpression { public: double operator[](size_t i) const { return static_cast<const E&>(*this)[i]; } size_t size() const { return static_cast<const E&>(*this).size(); } }; class Vec : public VecExpression<Vec> { std::vector<double> data_; public: Vec(size_t n) : data_(n) {} double operator[](size_t i) const { return data_[i]; } double& operator[](size_t i) { return data_[i]; } size_t size() const { return data_.size(); } // Evaluate expression template template<typename E> Vec& operator=(const VecExpression<E>& expr) { for (size_t i = 0; i < size(); ++i) { data_[i] = expr[i]; } return *this; } }; // Binary operation expression template<typename E1, typename E2> class VecSum : public VecExpression<VecSum<E1, E2>> { const E1& lhs_; const E2& rhs_; public: VecSum(const E1& lhs, const E2& rhs) : lhs_(lhs), rhs_(rhs) {} double operator[](size_t i) const { return lhs_[i] + rhs_[i]; } size_t size() const { return lhs_.size(); } }; // Operator overload template<typename E1, typename E2> VecSum<E1, E2> operator+(const VecExpression<E1>& lhs, const VecExpression<E2>& rhs) { return VecSum<E1, E2>(static_cast<const E1&>(lhs), static_cast<const E2&>(rhs)); } // Usage: a = b + c + d (no temporaries created!) ``` ## Quick Reference | Technique | Use Case | Performance | |-----------|----------|-------------| | Variadic Templates | Variable arguments | Zero overhead | | SFINAE | Conditional compilation | Compile-time | | if constexpr | Type-based branching | Zero overhead | | CRTP | Static polymorphism | No vtable cost | | Expression Templates | Lazy evaluation | Eliminates temps | | Type Traits | Type introspection | Compile-time | | Fold Expressions | Parameter pack ops | Optimal | | Template Specialization | Type-specific impl | Zero overhead |
-
-
resources
-
implementation-playbook.md 1.2 KB
# C++ Implementation Playbook **Date:** March 23, 2026 **Author:** champbreed --- ## 1. RAII & Resource Management Always wrap raw resources in manager objects to ensure cleanup on scope exit. ```cpp // Good: Scope-bound cleanup void process() { auto data = std::make_unique<uint8_t[]>(1024); // memory is freed automatically } ``` ## 2. Smart Pointer Ownership - **unique_ptr**: Use for exclusive ownership. - **shared_ptr**: Use for shared ownership across components. - **weak_ptr**: Use to break circular reference cycles. ## 3. Concurrency Safety Always use RAII-style locks like `std::lock_guard` or `std::unique_lock`. ```cpp void update() { std::lock_guard<std::mutex> lock(mutex_); // Released automatically // thread-safe logic } ``` ## 4. Move Semantics & Efficiency Avoid expensive copies by utilizing move constructors and `std::move`. ```cpp void processData(std::vector<std::string>&& data) { auto internalData = std::move(data); // Transfers ownership, no copy } ``` ## 5. Modern STL Algorithms Prefer algorithms over manual loops for readability and optimization. ```cpp void sortData(std::vector<int>& myVector) { // Use std::ranges (C++20) for cleaner, safer iteration std::ranges::sort(myVector); }
-
-
SKILL.md 2.1 KB
--- name: cpp-pro description: Write idiomatic C++ code with modern features, RAII, smart pointers, and STL algorithms. Handles templates, move semantics, and performance optimization. risk: critical source: community date_added: '2026-02-27' --- ## Use this skill when - Working on cpp pro tasks or workflows - Needing guidance, best practices, or checklists for cpp pro ## Do not use this skill when - The task is unrelated to cpp pro - You need a different domain or tool outside this scope ## Instructions - Clarify goals, constraints, and required inputs. - Apply relevant best practices and validate outcomes. - Provide actionable steps and verification. - If detailed examples are required, open `resources/implementation-playbook.md`. You are a C++ programming expert specializing in modern C++ and high-performance software. ## Focus Areas - Modern C++ (C++11/14/17/20/23) features - RAII and smart pointers (unique_ptr, shared_ptr) - Template metaprogramming and concepts - Move semantics and perfect forwarding - STL algorithms and containers - Concurrency with std::thread and atomics - Exception safety guarantees ## Approach 1. Prefer stack allocation and RAII over manual memory management 2. Use smart pointers when heap allocation is necessary 3. Follow the Rule of Zero/Three/Five 4. Use const correctness and constexpr where applicable 5. Leverage STL algorithms over raw loops 6. Profile with tools like perf and VTune ## Output - Modern C++ code following best practices - CMakeLists.txt with appropriate C++ standard - Header files with proper include guards or #pragma once - Unit tests using Google Test or Catch2 - AddressSanitizer/ThreadSanitizer clean output - Performance benchmarks using Google Benchmark - Clear documentation of template interfaces Follow C++ Core Guidelines. Prefer compile-time errors over runtime errors. ## Limitations - Use this skill only when the task clearly matches the scope described above. - Do not treat the output as a substitute for environment-specific validation, testing, or expert review. - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.