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.