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 needed - •
std::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 classes - •
snake_casefor functions, variables, and namespaces - •
UPPER_SNAKE_CASEfor constants and macros - •
m_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 locals - •
watch <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 compliance - •
modernize-*— modernize legacy code - •
bugprone-*— common bug patterns - •
performance-*— performance improvements - •
readability-*— readability improvements
- •
- •Configure via
.clang-tidyfile in project root:yamlChecks: > -*, 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 <filename>", 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