C++ Development Skill (Memory-Safe, Cross-Platform)
Assist with all aspects of modern C++ development with a strong emphasis on memory safety and cross-platform portability. This includes creating files, writing code, building projects, running executables, debugging, and testing.
Creating New Files
When creating a new C++ source file (.cpp) or header (.hpp/.h), always include the file header from CLAUDE.md using the /* */ comment template (C, C++, Objective-C, Swift style).
Source file template (.cpp):
/*****************************************************************************************
* example.cpp
*
* brief summary of the file contents
*
* Author : Gary Ash <gary.ash@icloud.com>
* Created : <current date/time>
* Modified :
*
* Copyright © <year> By Gary Ash All rights reserved.
****************************************************************************************/
#include "example.hpp"
Header file template (.hpp):
/*****************************************************************************************
* example.hpp
*
* brief summary of the file contents
*
* Author : Gary Ash <gary.ash@icloud.com>
* Created : <current date/time>
* Modified :
*
* Copyright © <year> By Gary Ash All rights reserved.
****************************************************************************************/
#pragma once
Prefer .hpp/.cpp extensions for C++ files. Use #pragma once instead of #ifndef include guards.
C++ Standard
- Target C++20 as the default standard unless the project specifies otherwise
- Use C++23 features only when the project explicitly opts in
- Set the standard in CMake:
set(CMAKE_CXX_STANDARD 20)withset(CMAKE_CXX_STANDARD_REQUIRED ON)
Memory Safety (Critical)
Memory safety is the top priority. Apply these rules strictly:
Ownership and Lifetime
- Never use raw
new/delete— use smart pointers or containers instead std::unique_ptrfor single-owner resources (default choice)std::shared_ptronly when shared ownership is genuinely neededstd::weak_ptrto break reference cycles withshared_ptr- Use
std::make_uniqueandstd::make_shared— never construct smart pointers from rawnew - Apply RAII (Resource Acquisition Is Initialization) for all resource management: files, locks, sockets, handles
Containers and References
- Use
std::vector,std::array,std::string,std::string_viewinstead of raw arrays and C strings - Use
std::span(C++20) for non-owning views over contiguous data - Use
std::optionalinstead of nullable raw pointers for optional values - Use
std::variantinstead of unions - Prefer references over pointers when null is not a valid state
- Prefer
const&for read-only access to non-trivial types
Array and Buffer Safety
- Use
.at()for bounds-checked access during development/debug builds - Use
std::rangesalgorithms instead of raw pointer iteration - Never perform pointer arithmetic on raw pointers — use
std::spanor iterators - Always validate sizes before buffer operations
Concurrency Safety
- Use
std::mutexwithstd::lock_guardorstd::scoped_lock— never manual lock/unlock - Use
std::atomicfor lock-free shared state - Use
std::jthread(C++20) overstd::threadfor automatic joining - Prefer
std::async/std::futurefor simple parallelism
Error Handling
- Use exceptions for exceptional conditions or
std::expected(C++23) /std::optionalfor expected failures - Never ignore return values — use
[[nodiscard]]on functions whose return value must be checked - Avoid
std::terminate/std::abortin library code - Use
static_assertfor compile-time invariants
Casts and Type Safety
- Never use C-style casts — use
static_cast,dynamic_cast,const_cast, orreinterpret_cast - Minimize use of
reinterpret_castandconst_cast— both are code smells - Use
enum classinstead of plainenum - Use
std::bytefor raw byte manipulation instead ofchar*orunsigned char*
Cross-Platform Development (Critical)
CMake (Required Build System)
Always use CMake for cross-platform builds. Minimum CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(ProjectName 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_executable(${PROJECT_NAME} src/main.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE include)
Key CMake practices:
- Always set
CMAKE_CXX_EXTENSIONS OFFto disable compiler-specific extensions - Use
target_*commands instead of globalinclude_directories()oradd_definitions() - Use
FetchContentorfind_packagefor dependencies - Export
compile_commands.jsonfor tooling:set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
Platform Abstraction
- Use
std::filesystemfor all path and file operations (not POSIX or Win32 APIs) - Use
std::chronofor all time operations - Use
<cstdint>fixed-width types:int32_t,uint64_t,size_t,ptrdiff_t - Use
std::thread/std::jthreadfor threading (not pthreads or Win32 threads) - Use
std::format(C++20) for string formatting - Avoid platform-specific headers (
<windows.h>,<unistd.h>) unless isolated behind abstractions
When Platform-Specific Code Is Needed
#if defined(_WIN32)
// Windows-specific code
#elif defined(__APPLE__)
// macOS/iOS-specific code
#elif defined(__linux__)
// Linux-specific code
#else
#error "Unsupported platform"
#endif
Isolate platform-specific code into dedicated source files with a common interface header.
Portability Rules
- Never assume endianness — use
std::endian(C++20) andstd::byteswap(C++23) when needed - Never assume
sizeof(int)or pointer sizes — use fixed-width types - Avoid compiler-specific attributes — use C++ standard
[[attributes]] - Use
std::source_location(C++20) instead of__FILE__/__LINE__macros - Avoid
#pragmadirectives other than#pragma once
Building and Running
Building with CMake
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
Build types:
- Debug:
-DCMAKE_BUILD_TYPE=Debug— full debug info, no optimization - Release:
-DCMAKE_BUILD_TYPE=Release— optimized, no debug info - RelWithDebInfo:
-DCMAKE_BUILD_TYPE=RelWithDebInfo— optimized with debug info - ASAN build: add
-DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer"and-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
Running
./build/ProjectName
Sanitizer Builds (Essential for Memory Safety)
Add a CMake option for sanitizers:
option(ENABLE_SANITIZERS "Enable ASan and UBSan" OFF)
if(ENABLE_SANITIZERS)
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
add_link_options(-fsanitize=address,undefined)
endif()
Build with sanitizers:
cmake -B build-asan -DENABLE_SANITIZERS=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build-asan
Available sanitizers (Clang/GCC):
- AddressSanitizer (ASan):
-fsanitize=address— buffer overflows, use-after-free, memory leaks - UndefinedBehaviorSanitizer (UBSan):
-fsanitize=undefined— signed overflow, null dereference, alignment - ThreadSanitizer (TSan):
-fsanitize=thread— data races (cannot combine with ASan) - MemorySanitizer (MSan):
-fsanitize=memory— uninitialized reads (Clang only, cannot combine with ASan)
Always run the test suite under ASan+UBSan before considering code complete.
Code Quality
Modern C++ Idioms
- Use structured bindings:
auto [key, value] = *map.begin(); - Use
if constexprfor compile-time branching - Use concepts (C++20) to constrain templates
- Use
autofor complex types but be explicit for readability at interfaces - Use
constexprandconstevalaggressively for compile-time computation - Use designated initializers (C++20):
Point{.x = 1, .y = 2} - Use range-based
forwith structured bindings:for (const auto& [k, v] : map) - Mark single-argument constructors
explicit - Follow the Rule of Zero: rely on compiler-generated special members by using smart pointers and standard containers
- If you must define one special member function, follow the Rule of Five
Naming Conventions
PascalCasefor types and classessnake_casefor functions, variables, and namespacesUPPER_SNAKE_CASEfor constants and macrosm_prefix for private member variables- Avoid Hungarian notation
Header Hygiene
- Include what you use — do not rely on transitive includes
- Use forward declarations where possible to reduce compile times
- Order includes: own header first, project headers, third-party headers, standard library
- Keep headers self-contained (every header compiles on its own)
Debugging
LLDB (primary on macOS)
- Launch:
lldb ./build/ProjectName - Key commands:
r(run),n(next),s(step into),c(continue),finish(step out)b <function>orb <file>:<line>(set breakpoint)br list(list breakpoints),br del <n>(delete breakpoint)p <expr>(print),po <expr>(print object/formatted)bt(backtrace),frame variable(show locals)watchpoint set variable <var>(data breakpoint)q(quit)
GDB (primary on Linux)
- Launch:
gdb ./build/ProjectName - Key commands:
r(run),n(next),s(step into),c(continue),finish(step out)b <function>orb <file>:<line>(set breakpoint)info b(list breakpoints),d <n>(delete breakpoint)p <expr>(print),bt(backtrace),info localswatch <expr>(data breakpoint)q(quit)
Valgrind (Linux)
- Memory error detection:
valgrind --leak-check=full ./build/ProjectName - Detailed:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./build/ProjectName
Static Analysis
clang-tidy
- Run:
clang-tidy src/*.cpp -- -std=c++20 -Iinclude - With compile_commands.json:
clang-tidy -p build src/*.cpp - Fix in place:
clang-tidy -fix -p build src/*.cpp - Key check categories:
cppcoreguidelines-*— C++ Core Guidelines compliancemodernize-*— modernize legacy codebugprone-*— common bug patternsperformance-*— performance improvementsreadability-*— readability improvements
- Configure via
.clang-tidyfile in project root:Checks: > -*, bugprone-*, cppcoreguidelines-*, modernize-*, performance-*, readability-* WarningsAsErrors: 'bugprone-*'
cppcheck
- Run:
cppcheck --enable=all --std=c++20 --suppress=missingIncludeSystem src/ - Check a single file:
cppcheck --enable=all --std=c++20 src/file.cpp
Compiler Warnings (Always Enable)
Add to CMakeLists.txt:
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
target_compile_options(${PROJECT_NAME} PRIVATE
-Wall -Wextra -Wpedantic -Werror
-Wconversion -Wsign-conversion
-Wnon-virtual-dtor -Wold-style-cast
-Wcast-align -Wunused -Woverloaded-virtual
-Wshadow -Wnull-dereference
-Wdouble-promotion -Wformat=2
-Wimplicit-fallthrough
)
elseif(MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE
/W4 /WX /permissive-
/w14640 /w14826 /w14928
)
endif()
Testing
Google Test (recommended)
Add via CMake FetchContent:
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.15.2
)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(tests tests/test_main.cpp)
target_link_libraries(tests PRIVATE GTest::gtest_main)
include(GoogleTest)
gtest_discover_tests(tests)
Test file structure:
#include <gtest/gtest.h>
#include "my_module.hpp"
TEST(MyModuleTest, BasicOperation) {
auto result = my_function(1, 2);
EXPECT_EQ(result, 3);
}
TEST(MyModuleTest, EdgeCase) {
EXPECT_THROW(my_function(-1, 0), std::invalid_argument);
}
TEST(MyModuleTest, NoLeaks) {
auto ptr = create_resource();
ASSERT_NE(ptr, nullptr);
// unique_ptr ensures cleanup — no manual delete needed
}
Run tests:
cmake --build build
ctest --test-dir build --output-on-failure
Catch2 (alternative)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.7.1
)
FetchContent_MakeAvailable(Catch2)
add_executable(tests tests/test_main.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)
Common Cross-Platform Dependency Management
FetchContent (preferred for small deps)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 11.1.4
)
FetchContent_MakeAvailable(fmt)
target_link_libraries(${PROJECT_NAME} PRIVATE fmt::fmt)
vcpkg
vcpkg install fmt nlohmann-json
cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
Conan
conan install . --build=missing
cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
Argument Handling
- If
$ARGUMENTSis a filename ending in.cpp,.hpp,.h, or.cc, work with that file - If
$ARGUMENTSis "new ", scaffold a new file with proper headers - If
$ARGUMENTSis "build", configure and build the CMake project - If
$ARGUMENTSis "run", build and run the project executable - If
$ARGUMENTSis "test", build and run the test suite - If
$ARGUMENTSis "check", run clang-tidy and cppcheck on the source tree - If
$ARGUMENTSis "sanitize", build with ASan+UBSan and run the test suite - Otherwise, treat
$ARGUMENTSas a general C++ development request