AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Cpp Coding Standards

skill-affaan-m-ecc-cpp-coding-standards · by affaan-m

C++ coding standards based on the C++ Core Guidelines (isocpp.github.io). Use when writing, reviewing, or refactoring C++ code to enforce modern, safe, and idiomatic practices.

— No reviews yet
0 installs
33 views
0.0% view→install

Install

$ agentstack add skill-affaan-m-ecc-cpp-coding-standards

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ● Filesystem access Used
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-affaan-m-ecc-cpp-coding-standards)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Cpp Coding Standards? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

C++ Coding Standards (C++ Core Guidelines)

Comprehensive coding standards for modern C++ (C++17/20/23) derived from the C++ Core Guidelines. Enforces type safety, resource safety, immutability, and clarity.

When to Use

  • Writing new C++ code (classes, functions, templates)
  • Reviewing or refactoring existing C++ code
  • Making architectural decisions in C++ projects
  • Enforcing consistent style across a C++ codebase
  • Choosing between language features (e.g., enum vs enum class, raw pointer vs smart pointer)

When NOT to Use

  • Non-C++ projects
  • Legacy C codebases that cannot adopt modern C++ features
  • Embedded/bare-metal contexts where specific guidelines conflict with hardware constraints (adapt selectively)

Cross-Cutting Principles

These themes recur across the entire guidelines and form the foundation:

  1. RAII everywhere (P.8, R.1, E.6, CP.20): Bind resource lifetime to object lifetime
  2. Immutability by default (P.10, Con.1-5, ES.25): Start with const/constexpr; mutability is the exception
  3. Type safety (P.4, I.4, ES.46-49, Enum.3): Use the type system to prevent errors at compile time
  4. Express intent (P.3, F.1, NL.1-2, T.10): Names, types, and concepts should communicate purpose
  5. Minimize complexity (F.2-3, ES.5, Per.4-5): Simple code is correct code
  6. Value semantics over pointer semantics (C.10, R.3-5, F.20, CP.31): Prefer returning by value and scoped objects

Philosophy & Interfaces (P., I.)

Key Rules

| Rule | Summary | |------|---------| | P.1 | Express ideas directly in code | | 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.8 | Don't leak any resources | | P.10 | Prefer immutable data to mutable data | | I.1 | Make interfaces explicit | | I.2 | Avoid non-const global variables | | I.4 | Make interfaces precisely and strongly typed | | I.11 | Never transfer ownership by a raw pointer or reference | | I.23 | Keep the number of function arguments low |

DO

// P.10 + I.4: Immutable, strongly typed interface
struct Temperature {
    double kelvin;
};

Temperature boil(const Temperature& water);

DON'T

// Weak interface: unclear ownership, unclear units
double boil(double* temp);

// Non-const global variable
int g_counter = 0;  // I.2 violation

Functions (F.*)

Key Rules

| Rule | Summary | |------|---------| | 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 be evaluated at compile time, declare it constexpr | | F.6 | If your function must not throw, declare it noexcept | | F.8 | Prefer pure functions | | F.16 | For "in" parameters, pass cheaply-copied types by value and others by const& | | F.20 | For "out" values, prefer return values to output parameters | | F.21 | To return multiple "out" values, prefer returning a struct | | F.43 | Never return a pointer or reference to a local object |

Parameter Passing

// F.16: Cheap types by value, others by const&
void print(int x);                           // cheap: by value
void analyze(const std::string& data);       // expensive: by const&
void transform(std::string s);               // sink: by value (will move)

// F.20 + F.21: Return values, not output parameters
struct ParseResult {
    std::string token;
    int position;
};

ParseResult parse(std::string_view input);   // GOOD: return struct

// BAD: output parameters
void parse(std::string_view input,
           std::string& token, int& pos);    // avoid this

Pure Functions and constexpr

// F.4 + F.8: Pure, constexpr where possible
constexpr int factorial(int n) noexcept {
    return (n (size)), size_(size) {}

    ~Buffer() = default;

    Buffer(const Buffer& other)
        : data_(std::make_unique(other.size_)), size_(other.size_) {
        std::copy_n(other.data_.get(), size_, data_.get());
    }

    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            auto new_data = std::make_unique(other.size_);
            std::copy_n(other.data_.get(), other.size_, new_data.get());
            data_ = std::move(new_data);
            size_ = other.size_;
        }
        return *this;
    }

    Buffer(Buffer&&) noexcept = default;
    Buffer& operator=(Buffer&&) noexcept = default;

private:
    std::unique_ptr data_;
    std::size_t size_;
};

Class Hierarchy

// C.35 + C.128: Virtual destructor, use override
class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;  // C.121: pure interface
};

class Circle : public Shape {
public:
    explicit Circle(double r) : radius_(r) {}
    double area() const override { return 3.14159 * radius_ * radius_; }

private:
    double radius_;
};

Anti-Patterns

  • Calling virtual functions in constructors/destructors (C.82)
  • Using memset/memcpy on non-trivial types (C.90)
  • Providing different default arguments for virtual function and overrider (C.140)
  • Making data members const or references, which suppresses move/copy (C.12)

Resource Management (R.*)

Key Rules

| Rule | Summary | |------|---------| | R.1 | Manage resources automatically using RAII | | R.3 | A raw pointer (T*) is non-owning | | R.5 | Prefer scoped objects; don't heap-allocate unnecessarily | | R.10 | Avoid malloc()/free() | | R.11 | Avoid calling new and delete explicitly | | R.20 | Use unique_ptr or shared_ptr to represent ownership | | R.21 | Prefer unique_ptr over shared_ptr unless sharing ownership | | R.22 | Use make_shared() to make shared_ptrs |

Smart Pointer Usage

// R.11 + R.20 + R.21: RAII with smart pointers
auto widget = std::make_unique("config");  // unique ownership
auto cache  = std::make_shared(1024);        // shared ownership

// R.3: Raw pointer = non-owning observer
void render(const Widget* w) {  // does NOT own w
    if (w) w->draw();
}

render(widget.get());

RAII Pattern

// R.1: Resource acquisition is initialization
class FileHandle {
public:
    explicit FileHandle(const std::string& path)
        : handle_(std::fopen(path.c_str(), "r")) {
        if (!handle_) throw std::runtime_error("Failed to open: " + path);
    }

    ~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;
    }

private:
    std::FILE* handle_;
};

Anti-Patterns

  • Naked new/delete (R.11)
  • malloc()/free() in C++ code (R.10)
  • Multiple resource allocations in a single expression (R.13 -- exception safety hazard)
  • shared_ptr where unique_ptr suffices (R.21)

Expressions & Statements (ES.*)

Key Rules

| Rule | Summary | |------|---------| | ES.5 | Keep scopes small | | ES.20 | Always initialize an object | | ES.23 | Prefer {} initializer syntax | | ES.25 | Declare objects const or constexpr unless modification is intended | | ES.28 | Use lambdas for complex initialization of const variables | | ES.45 | Avoid magic constants; use symbolic constants | | ES.46 | Avoid narrowing/lossy arithmetic conversions | | ES.47 | Use nullptr rather than 0 or NULL | | ES.48 | Avoid casts | | ES.50 | Don't cast away const |

Initialization

// ES.20 + ES.23 + ES.25: Always initialize, prefer {}, default to const
const int max_retries{3};
const std::string name{"widget"};
const std::vector primes{2, 3, 5, 7, 11};

// ES.28: Lambda for complex const initialization
const auto config = [&] {
    Config c;
    c.timeout = std::chrono::seconds{30};
    c.retries = max_retries;
    c.verbose = debug_mode;
    return c;
}();

Anti-Patterns

  • Uninitialized variables (ES.20)
  • Using 0 or NULL as pointer (ES.47 -- use nullptr)
  • C-style casts (ES.48 -- use static_cast, const_cast, etc.)
  • Casting away const (ES.50)
  • Magic numbers without named constants (ES.45)
  • Mixing signed and unsigned arithmetic (ES.100)
  • Reusing names in nested scopes (ES.12)

Error Handling (E.*)

Key Rules

| Rule | Summary | |------|---------| | 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.6 | Use RAII to prevent leaks | | E.12 | Use noexcept when throwing is impossible or unacceptable | | E.14 | Use purpose-designed user-defined types as exceptions | | E.15 | Throw by value, catch by reference | | E.16 | Destructors, deallocation, and swap must never fail | | E.17 | Don't try to catch every exception in every function |

Exception Hierarchy

// E.14 + E.15: Custom exception types, throw by value, catch by reference
class AppError : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};

class NetworkError : public AppError {
public:
    NetworkError(const std::string& msg, int code)
        : AppError(msg), status_code(code) {}
    int status_code;
};

void fetch_data(const std::string& url) {
    // E.2: Throw to signal failure
    throw NetworkError("connection refused", 503);
}

void run() {
    try {
        fetch_data("https://api.example.com");
    } catch (const NetworkError& e) {
        log_error(e.what(), e.status_code);
    } catch (const AppError& e) {
        log_error(e.what());
    }
    // E.17: Don't catch everything here -- let unexpected errors propagate
}

Anti-Patterns

  • Throwing built-in types like int or string literals (E.14)
  • Catching by value (slicing risk) (E.15)
  • Empty catch blocks that silently swallow errors
  • Using exceptions for flow control (E.3)
  • Error handling based on global state like errno (E.28)

Constants & Immutability (Con.*)

All Rules

| Rule | Summary | |------|---------| | Con.1 | By default, make objects immutable | | Con.2 | By default, make member functions const | | Con.3 | By default, pass pointers and references to const | | Con.4 | Use const for values that don't change after construction | | Con.5 | Use constexpr for values computable at compile time |

// Con.1 through Con.5: Immutability by default
class Sensor {
public:
    explicit Sensor(std::string id) : id_(std::move(id)) {}

    // Con.2: const member functions by default
    const std::string& id() const { return id_; }
    double last_reading() const { return reading_; }

    // Only non-const when mutation is required
    void record(double value) { reading_ = value; }

private:
    const std::string id_;  // Con.4: never changes after construction
    double reading_{0.0};
};

// Con.3: Pass by const reference
void display(const Sensor& s) {
    std::cout  lock(mutex_);  // CP.44: named!
        queue_.push(value);
        cv_.notify_one();
    }

    int pop() {
        std::unique_lock lock(mutex_);
        // CP.42: Always wait with a condition
        cv_.wait(lock, [this] { return !queue_.empty(); });
        const int value = queue_.front();
        queue_.pop();
        return value;
    }

private:
    std::mutex mutex_;             // CP.50: mutex with its data
    std::condition_variable cv_;
    std::queue queue_;
};

Multiple Mutexes

// CP.21: std::scoped_lock for multiple mutexes (deadlock-free)
void transfer(Account& from, Account& to, double amount) {
    std::scoped_lock lock(from.mutex_, to.mutex_);
    from.balance_ -= amount;
    to.balance_ += amount;
}

Anti-Patterns

  • volatile for synchronization (CP.8 -- it's for hardware I/O only)
  • Detaching threads (CP.26 -- lifetime management becomes nearly impossible)
  • Unnamed lock guards: std::lock_guard(m); destroys immediately (CP.44)
  • Holding locks while calling callbacks (CP.22 -- deadlock risk)
  • Lock-free programming without deep expertise (CP.100)

Templates & Generic Programming (T.*)

Key Rules

| Rule | Summary | |------|---------| | T.1 | Use templates to raise the level of abstraction | | T.2 | Use templates to express algorithms for many argument types | | T.10 | Specify concepts for all template arguments | | T.11 | Use standard concepts whenever possible | | T.13 | Prefer shorthand notation for simple concepts | | T.43 | Prefer using over typedef | | T.120 | Use template metaprogramming only when you really need to | | T.144 | Don't specialize function templates (overload instead) |

Concepts (C++20)

#include 

// T.10 + T.11: Constrain templates with standard concepts
template
T gcd(T a, T b) {
    while (b != 0) {
        a = std::exchange(b, a % b);
    }
    return a;
}

// T.13: Shorthand concept syntax
void sort(std::ranges::random_access_range auto& range) {
    std::ranges::sort(range);
}

// Custom concept for domain-specific constraints
template
concept Serializable = requires(const T& t) {
    { t.serialize() } -> std::convertible_to;
};

template
void save(const T& obj, const std::string& path);

Anti-Patterns

  • Unconstrained templates in visible namespaces (T.47)
  • Specializing function templates instead of overloading (T.144)
  • Template metaprogramming where constexpr suffices (T.120)
  • typedef instead of using (T.43)

Standard Library (SL.*)

Key Rules

| Rule | Summary | |------|---------| | SL.1 | Use libraries wherever possible | | SL.2 | Prefer the standard library to other libraries | | SL.con.1 | Prefer std::array or std::vector over C arrays | | SL.con.2 | Prefer std::vector by default | | SL.str.1 | Use std::string to own character sequences | | SL.str.2 | Use std::string_view to refer to character sequences | | SL.io.50 | Avoid endl (use '\n' -- endl forces a flush) |

// SL.con.1 + SL.con.2: Prefer vector/array over C arrays
const std::array fixed_data{1, 2, 3, 4};
std::vector dynamic_data;

// SL.str.1 + SL.str.2: string owns, string_view observes
std::string build_greeting(std::string_view name) {
    return "Hello, " + std::string(name) + "!";
}

// SL.io.50: Use '\n' not endl
std::cout 
#include 

namespace project::module {

class Widget {
public:
    explicit Widget(std::string name);
    const std::string& name() const;

private:
    std::string name_;
};

}  // namespace project::module

#endif  // PROJECT_MODULE_WIDGET_H

Naming Conventions

// NL.8 + NL.10: Consistent underscore_style
namespace my_project {

constexpr int max_buffer_size = 4096;  // NL.9: not ALL_CAPS (it's not a macro)

class tcp_connection {                 // underscore_style class
public:
    void send_message(std::string_view msg);
    bool is_connected() const;

private:
    std::string host_;                 // trailing underscore for members
    int port_;
};

}  // namespace my_project

Anti-Patterns

  • using namespace std; in a header at global scope (SF.7)
  • Headers that depend on inclusion order (SF.10, SF.11)
  • Hungarian notation like strName, iCount (NL.5)
  • ALL_CAPS for anything other than macros (NL.9)

Performance (Per.*)

Key Rules

| Rule | Summary | |------|---------| | Per.1 | Don't optimize without reason | | Per.2 | Don't optimize prematurely | | Per.6 | Don't make claims about performance without measurement

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.