Skip to content

C++ Coding Standards

Overview

Coding standards are an important foundation for team collaboration and code maintenance. Good coding standards improve code readability, reduce errors, and promote team collaboration. This chapter covers various aspects of C++ coding standards, including naming conventions, formatting standards, and documentation standards.

📝 Naming Conventions

Variable and Function Naming

cpp
// ✅ Good naming
class UserAccount {
private:
    std::string username_;           // Member variables with underscore suffix
    std::string email_address_;      // Descriptive naming
    int account_id_;                 // lowercase + underscores
    
public:
    // Function names: verbs, camelCase
    void setUsername(const std::string& username);
    std::string getUsername() const;
    
    // Boolean functions start with is/has/can
    bool isActive() const;
    bool hasValidEmail() const;
    bool canLogin() const;
    
    // Private helper functions
    void validateInput_(const std::string& input);
};

// Local variables
void processUserData() {
    int user_count = 0;              // lowercase + underscores
    std::string temp_filename;       // Descriptive naming
    bool is_valid = false;           // Boolean variables clearly express intent
    
    // Loop variables can be short
    for (int i = 0; i < user_count; ++i) {
        // Processing logic
    }
    
    // Range-based for loops use descriptive names
    for (const auto& user : user_list) {
        // Process each user
    }
}

// ❌ Bad naming
class ua {                          // Class name too short
    std::string n;                  // Variable name meaningless
    int data;                       // Too generic
    
public:
    void DoSomething();             // Function name unclear
    bool Check();                   // Check what?
    int get();                      // Get what?
};

Class and Structure Naming

cpp
// ✅ Class naming conventions
class DatabaseConnection {          // PascalCase naming
    // Implementation
};

class HttpRequestHandler {          // Clear responsibility description
    // Implementation
};

struct ConfigurationSettings {      // Structures also use PascalCase
    std::string server_address;
    int port_number;
    bool enable_ssl;
};

// Template classes
template<typename T>
class SmartPointer {               // Template parameter T is concise and clear
    // Implementation
};

template<typename Container, typename Predicate>
class FilteredView {               // Descriptive template parameter naming
    // Implementation
};

// Enum classes
enum class ConnectionStatus {      // Enum classes use PascalCase
    kDisconnected,                 // Enum values use k prefix
    kConnecting,
    kConnected,
    kError
};

enum class LogLevel {
    kDebug = 0,
    kInfo = 1,
    kWarning = 2,
    kError = 3,
    kCritical = 4
};

Constants and Macros

cpp
// ✅ Constant naming
namespace config {
    // Compile-time constants
    constexpr int kMaxConnections = 100;
    constexpr double kPi = 3.14159265359;
    constexpr char kDefaultEncoding[] = "UTF-8";
    
    // Global constants
    const std::string kApplicationName = "MyApp";
    const std::chrono::seconds kTimeout{30};
}

// Class constants
class Buffer {
private:
    static constexpr size_t kDefaultSize = 1024;
    static constexpr size_t kMaxSize = 65536;
    
public:
    static const std::string kVersion;
};

// Macro definitions (should be avoided if possible)
#define MY_APP_VERSION_MAJOR 1
#define MY_APP_VERSION_MINOR 0
#define MY_APP_DEBUG_ENABLED 1

// Functional macros
#define ASSERT_MSG(condition, message) \
    do { \
        if (!(condition)) { \
            std::cerr << "Assertion failed: " << message << std::endl; \
            abort(); \
        } \
    } while(0)

🔧 Formatting Standards

Indentation and Spacing

cpp
// ✅ Correct indentation (use 4 spaces or 1 tab)
class Example {
public:
    void method() {
        if (condition) {
            for (int i = 0; i < count; ++i) {
                process(i);
            }
        }
    }
    
private:
    int member_variable_;
};

// Function parameter alignment
void longFunctionName(
    const std::string& first_parameter,
    const std::string& second_parameter,
    int third_parameter,
    bool fourth_parameter) {
    // Implementation
}

// Or
void longFunctionName(const std::string& first_parameter,
                     const std::string& second_parameter,
                     int third_parameter,
                     bool fourth_parameter) {
    // Implementation
}

Braces and Line Breaks

cpp
// ✅ Recommended brace style
namespace my_namespace {

class MyClass {
public:
    MyClass() {
        // Constructor implementation
    }
    
    void method() {
        if (condition) {
            // if statement body
        } else {
            // else statement body
        }
        
        for (int i = 0; i < count; ++i) {
            // Loop body
        }
        
        try {
            // Code to try
        } catch (const std::exception& e) {
            // Exception handling
        }
    }
    
private:
    int value_;
};

}  // namespace my_namespace

// Single-line can omit braces (but be cautious)
if (simple_condition) 
    simple_action();

// Complex expressions should use line breaks
if (very_long_condition_that_spans_multiple_lines &&
    another_condition_that_is_also_long &&
    yet_another_condition) {
    // Processing logic
}

Blank Lines and Spacing

cpp
// ✅ Reasonable use of blank lines
#include <iostream>
#include <string>
#include <vector>

namespace utilities {

const int kMaxRetries = 3;

class NetworkManager {
public:
    // Constructor
    NetworkManager();
    ~NetworkManager();
    
    // Main interface
    bool connect(const std::string& host, int port);
    void disconnect();
    
    // Data transfer
    bool sendData(const std::vector<uint8_t>& data);
    std::vector<uint8_t> receiveData();
    
private:
    // Private helper methods
    bool establishConnection_();
    void cleanup_();
    
    // Member variables
    std::string host_;
    int port_;
    bool is_connected_;
};

}  // namespace utilities

// Spaces around operators
int result = a + b * c;
bool is_valid = (x > 0) && (y < max_value);
array[index] = new_value;
function_call(param1, param2, param3);

// Spaces for pointers and references
int* pointer;                    // or int *pointer;
int& reference = value;          // or int &reference = value;
const std::string& name = getName();

📖 Documentation Standards

Documentation Comments

cpp
/**
 * @brief User account management class
 * 
 * This class is responsible for the creation, verification, and maintenance 
 * of user accounts. Supports multiple authentication methods and 
 * permission management.
 * 
 * @author John Doe
 * @version 1.2.0
 * @since 1.0.0
 * 
 * @example
 * ```cpp
 * UserManager manager;
 * if (manager.createUser("alice", "password123")) {
 *     std::cout << "User created successfully" << std::endl;
 * }
 * ```
 */
class UserManager {
public:
    /**
     * @brief Create a new user account
     * 
     * @param username Username, length should be between 3-20 characters
     * @param password Password, at least 8 characters, must contain letters and numbers
     * @return true if creation succeeds
     * @return false if creation fails (username already exists or invalid parameters)
     * 
     * @throws std::invalid_argument when username or password format is invalid
     * @throws std::runtime_error when database operation fails
     * 
     * @note Password will be automatically hashed
     * @warning This method is not thread-safe
     * 
     * @see validateUsername()
     * @see validatePassword()
     */
    bool createUser(const std::string& username, const std::string& password);
    
    /**
     * @brief Verify user credentials
     * 
     * @param username Username
     * @param password Plain text password
     * @return Returns user ID if verification succeeds, -1 if fails
     */
    int authenticateUser(const std::string& username, 
                        const std::string& password);
    
private:
    /**
     * @brief Validate username format
     * @param username Username to validate
     * @return true if format is correct
     */
    bool validateUsername_(const std::string& username);
};

Inline Comments

cpp
void processData() {
    // Initialize buffer
    std::vector<uint8_t> buffer(kBufferSize);
    
    // FIXME: Possible memory leak here
    int* temp_data = new int[size];
    
    // TODO: Optimize the performance of this algorithm
    for (int i = 0; i < data_count; ++i) {
        // Skip invalid data
        if (data[i] < 0) continue;
        
        // Apply complex transformation formula
        // y = ax² + bx + c
        double result = a * data[i] * data[i] + b * data[i] + c;
        
        processed_data.push_back(result);
    }
    
    // HACK: Temporary workaround, needs refactoring
    if (legacy_mode) {
        convertToLegacyFormat();
    }
    
    delete[] temp_data;  // Free temporary memory
}

// Comments for complex algorithms
void quickSort(std::vector<int>& arr, int low, int high) {
    if (low < high) {
        // Partition operation: Split array into two parts, less than and greater than pivot
        int pivot_index = partition(arr, low, high);
        
        // Recursively sort left half (less than pivot)
        quickSort(arr, low, pivot_index - 1);
        
        // Recursively sort right half (greater than pivot)
        quickSort(arr, pivot_index + 1, high);
    }
}

Special Comment Markers

cpp
class ApiClient {
public:
    // NOTE: This method will block the thread until the request completes
    std::string makeRequest(const std::string& url);
    
    // WARNING: This method is deprecated, please use makeAsyncRequest
    [[deprecated("Use makeAsyncRequest instead")]]
    std::string makeSyncRequest(const std::string& url);
    
    // XXX: Temporary implementation, needs rewriting
    void temporaryWorkaround();
    
private:
    // PERF: This function could become a performance bottleneck
    void heavyComputation();
    
    // SECURITY: Ensure debug output is disabled in production
    void debugLog(const std::string& message) {
        #ifdef DEBUG
        std::cout << "[DEBUG] " << message << std::endl;
        #endif
    }
};

📂 File Organization

Header File Standards

cpp
// user_manager.h
#ifndef USER_MANAGER_H_  // Prevent multiple inclusion
#define USER_MANAGER_H_

#include <string>       // Standard library headers
#include <vector>
#include <memory>

#include "base/object.h"    // Project internal headers
#include "common/types.h"

namespace myapp {
namespace auth {

// Forward declarations
class Database;
class Logger;

/**
 * @brief User manager class
 */
class UserManager {
public:
    // Type aliases
    using UserId = int64_t;
    using UserList = std::vector<std::string>;
    
    // Constructors and destructor
    explicit UserManager(std::shared_ptr<Database> db);
    ~UserManager();
    
    // Disable copy, allow move
    UserManager(const UserManager&) = delete;
    UserManager& operator=(const UserManager&) = delete;
    UserManager(UserManager&&) = default;
    UserManager& operator=(UserManager&&) = default;
    
    // Public interface
    bool createUser(const std::string& username, const std::string& password);
    UserId authenticateUser(const std::string& username, const std::string& password);
    
private:
    // Private members
    std::shared_ptr<Database> database_;
    std::unique_ptr<Logger> logger_;
    
    // Private methods
    bool validateCredentials_(const std::string& username, const std::string& password);
};

}  // namespace auth
}  // namespace myapp

#endif  // USER_MANAGER_H_

Implementation File Standards

cpp
// user_manager.cpp
#include "auth/user_manager.h"

#include <algorithm>    // Standard libraries
#include <cassert>
#include <stdexcept>

#include "base/database.h"      // Project headers
#include "common/logger.h"
#include "common/crypto_utils.h"

namespace myapp {
namespace auth {

namespace {  // Anonymous namespace for internal helper functions

constexpr int kMinUsernameLength = 3;
constexpr int kMaxUsernameLength = 20;
constexpr int kMinPasswordLength = 8;

bool isValidUsername(const std::string& username) {
    if (username.length() < kMinUsernameLength || 
        username.length() > kMaxUsernameLength) {
        return false;
    }
    
    return std::all_of(username.begin(), username.end(), 
                      [](char c) { return std::isalnum(c) || c == '_'; });
}

}  // namespace

UserManager::UserManager(std::shared_ptr<Database> db) 
    : database_(std::move(db)),
      logger_(std::make_unique<Logger>("UserManager")) {
    assert(database_ != nullptr);
    logger_->info("UserManager initialized");
}

UserManager::~UserManager() {
    logger_->info("UserManager destroyed");
}

bool UserManager::createUser(const std::string& username, 
                           const std::string& password) {
    logger_->debug("Creating user: {}", username);
    
    // Input validation
    if (!isValidUsername(username)) {
        logger_->warning("Invalid username: {}", username);
        return false;
    }
    
    if (password.length() < kMinPasswordLength) {
        logger_->warning("Password too short");
        return false;
    }
    
    // Check if user already exists
    if (database_->userExists(username)) {
        logger_->warning("User already exists: {}", username);
        return false;
    }
    
    try {
        // Hash password
        std::string hashed_password = crypto::hashPassword(password);
        
        // Save to database
        UserId user_id = database_->createUser(username, hashed_password);
        
        logger_->info("User created successfully: {} (ID: {})", username, user_id);
        return true;
        
    } catch (const std::exception& e) {
        logger_->error("Failed to create user {}: {}", username, e.what());
        return false;
    }
}

}  // namespace auth
}  // namespace myapp

🛡️ Code Quality Standards

Error Handling

cpp
// ✅ Good error handling
class FileManager {
public:
    enum class ErrorCode {
        kSuccess,
        kFileNotFound,
        kPermissionDenied,
        kInsufficientSpace,
        kCorruptedData
    };
    
    struct Result {
        ErrorCode error_code;
        std::string error_message;
        
        bool isSuccess() const { return error_code == ErrorCode::kSuccess; }
    };
    
    // Use result type instead of exceptions
    Result readFile(const std::string& filename, std::string& content) {
        if (filename.empty()) {
            return {ErrorCode::kFileNotFound, "Filename cannot be empty"};
        }
        
        std::ifstream file(filename);
        if (!file.is_open()) {
            return {ErrorCode::kFileNotFound, "Cannot open file: " + filename};
        }
        
        try {
            content = std::string(std::istreambuf_iterator<char>(file),
                                 std::istreambuf_iterator<char>());
            return {ErrorCode::kSuccess, ""};
        } catch (const std::exception& e) {
            return {ErrorCode::kCorruptedData, "Error reading file: " + std::string(e.what())};
        }
    }
    
    // Exceptions only for truly exceptional cases
    void writeFile(const std::string& filename, const std::string& content) {
        if (filename.empty()) {
            throw std::invalid_argument("Filename cannot be empty");
        }
        
        std::ofstream file(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Cannot create file: " + filename);
        }
        
        file << content;
        if (file.fail()) {
            throw std::runtime_error("Error writing to file: " + filename);
        }
    }
};

Resource Management

cpp
// ✅ RAII resource management
class DatabaseConnection {
public:
    explicit DatabaseConnection(const std::string& connection_string) {
        connection_ = openConnection(connection_string);
        if (!connection_) {
            throw std::runtime_error("Failed to connect to database");
        }
    }
    
    ~DatabaseConnection() {
        if (connection_) {
            closeConnection(connection_);
        }
    }
    
    // Disable copy, allow move
    DatabaseConnection(const DatabaseConnection&) = delete;
    DatabaseConnection& operator=(const DatabaseConnection&) = delete;
    
    DatabaseConnection(DatabaseConnection&& other) noexcept
        : connection_(std::exchange(other.connection_, nullptr)) {}
    
    DatabaseConnection& operator=(DatabaseConnection&& other) noexcept {
        if (this != &other) {
            if (connection_) {
                closeConnection(connection_);
            }
            connection_ = std::exchange(other.connection_, nullptr);
        }
        return *this;
    }
    
    void execute(const std::string& query) {
        if (!connection_) {
            throw std::runtime_error("No active connection");
        }
        // Execute query
    }
    
private:
    void* connection_ = nullptr;  // Actual connection handle
    
    void* openConnection(const std::string& connection_string);
    void closeConnection(void* connection);
};

Performance Considerations

cpp
// ✅ Performance-optimized code
class StringProcessor {
public:
    // Avoid unnecessary copies
    std::vector<std::string> processStrings(const std::vector<std::string>& input) {
        std::vector<std::string> result;
        result.reserve(input.size());  // Pre-allocate memory
        
        for (const auto& str : input) {  // Range-based for loop, avoid copy
            if (str.empty()) continue;
            
            result.emplace_back(transformString(str));  // In-place construction
        }
        
        return result;
    }
    
    // Move semantics
    void addString(std::string str) {  // Pass by value, support move
        if (str.empty()) return;
        
        strings_.emplace_back(std::move(str));  // Move to container
    }
    
    // String view to avoid copy
    bool containsSubstring(std::string_view text, std::string_view pattern) {
        return text.find(pattern) != std::string_view::npos;
    }
    
private:
    std::vector<std::string> strings_;
    
    std::string transformString(const std::string& input) {
        // String transformation logic
        std::string result;
        result.reserve(input.size() * 2);  // Estimate result size
        
        for (char c : input) {
            if (std::isalpha(c)) {
                result += std::toupper(c);
            }
        }
        
        return result;
    }
};

Summary

Naming Convention Summary

  • Class names: PascalCase (UserAccount)
  • Function names: camelCase (getUserName)
  • Variable names: snake_case (user_name)
  • Member variables: snake_case + underscore suffix (user_name_)
  • Constants: k prefix + PascalCase (kMaxSize)
  • Enum values: k prefix + PascalCase (kConnected)

Formatting Guidelines

  • Indentation: 4 spaces or 1 tab
  • Line length: Recommended not to exceed 80-100 characters
  • Braces: Recommend Allman or K&R style, maintain consistency
  • Spaces: Add spaces around operators
  • Blank lines: Add blank lines between logical blocks

Documentation Guidelines

  • Documentation comments: Use Doxygen format
  • Inline comments: Explain why, not what
  • Special markers: TODO, FIXME, NOTE, WARNING
  • Self-documenting code: Excellent naming reduces comment needs

Code Quality Requirements

  • Error handling: Clear error handling strategy
  • Resource management: Follow RAII principles
  • Performance awareness: Avoid unnecessary copies and allocations
  • Thread safety: Clearly mark thread safety
  • Testability: Design interfaces that are easy to test

Tool Support

  • Formatting: clang-format
  • Static analysis: clang-tidy, cppcheck
  • Documentation generation: Doxygen
  • Code review: Integrate into CI/CD workflow

Coding standards are not just style issues, but the foundation of code quality and team collaboration. Establishing and following consistent coding standards can significantly improve project maintainability and development efficiency.

Content is for learning and research only.