Skip to content

C++ 最佳实践

概述

C++最佳实践是经过实践检验的编程技巧和设计原则,能帮助开发者写出更安全、高效、可维护的代码。本章总结了现代C++开发中的核心最佳实践,涵盖内存管理、性能优化、设计模式等方面。

🔒 内存管理最佳实践

RAII原则

cpp
#include <memory>
#include <fstream>
#include <vector>
#include <mutex>

// ✅ RAII - 资源获取即初始化
class FileHandler {
private:
    std::unique_ptr<std::FILE, decltype(&std::fclose)> file_;
    
public:
    explicit FileHandler(const std::string& filename) 
        : file_(std::fopen(filename.c_str(), "r"), &std::fclose) {
        if (!file_) {
            throw std::runtime_error("Cannot open file: " + filename);
        }
    }
    
    // 析构函数自动清理资源
    ~FileHandler() = default;  // unique_ptr自动调用deleter
    
    std::string readLine() {
        if (!file_) return "";
        
        std::string line;
        char buffer[256];
        if (std::fgets(buffer, sizeof(buffer), file_.get())) {
            line = buffer;
        }
        return line;
    }
};

// ✅ 自定义RAII包装器
class MutexLock {
private:
    std::mutex& mutex_;
    
public:
    explicit MutexLock(std::mutex& m) : mutex_(m) {
        mutex_.lock();
    }
    
    ~MutexLock() {
        mutex_.unlock();
    }
    
    // 禁用拷贝和赋值
    MutexLock(const MutexLock&) = delete;
    MutexLock& operator=(const MutexLock&) = delete;
};

// 使用示例
void processFile(const std::string& filename) {
    try {
        FileHandler handler(filename);
        std::string line = handler.readLine();
        // 文件会在作用域结束时自动关闭
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

智能指针使用

cpp
#include <memory>
#include <vector>

class Resource {
public:
    Resource(int id) : id_(id) {
        std::cout << "Resource " << id_ << " created\n";
    }
    
    ~Resource() {
        std::cout << "Resource " << id_ << " destroyed\n";
    }
    
    void process() {
        std::cout << "Processing resource " << id_ << "\n";
    }
    
private:
    int id_;
};

class ResourceManager {
public:
    // ✅ 使用unique_ptr表示独占所有权
    std::unique_ptr<Resource> createResource(int id) {
        return std::make_unique<Resource>(id);
    }
    
    // ✅ 使用shared_ptr表示共享所有权
    std::shared_ptr<Resource> createSharedResource(int id) {
        return std::make_shared<Resource>(id);
    }
    
    // ✅ 传递智能指针的最佳实践
    void processResource(const std::unique_ptr<Resource>& resource) {
        if (resource) {
            resource->process();
        }
    }
    
    void shareResource(std::shared_ptr<Resource> resource) {  // 按值传递shared_ptr
        shared_resources_.push_back(std::move(resource));
    }
    
    // ✅ 返回原始指针进行观察
    Resource* findResource(int id) {
        for (const auto& resource : shared_resources_) {
            if (resource && resource.get()->getId() == id) {
                return resource.get();
            }
        }
        return nullptr;
    }
    
private:
    std::vector<std::shared_ptr<Resource>> shared_resources_;
};

// ✅ 工厂函数返回智能指针
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_resource(Args&&... args) {
    return std::make_unique<T>(std::forward<Args>(args)...);
}

// 使用示例
void demonstrateSmartPointers() {
    ResourceManager manager;
    
    // 独占所有权
    auto unique_resource = manager.createResource(1);
    manager.processResource(unique_resource);
    
    // 共享所有权
    auto shared_resource = manager.createSharedResource(2);
    manager.shareResource(shared_resource);
    
    // weak_ptr避免循环引用
    std::weak_ptr<Resource> weak_ref = shared_resource;
    if (auto locked = weak_ref.lock()) {
        locked->process();
    }
}

⚡ 性能优化最佳实践

移动语义和完美转发

cpp
#include <string>
#include <vector>
#include <utility>

class DataContainer {
private:
    std::vector<std::string> data_;
    std::string name_;
    
public:
    // ✅ 支持移动的构造函数
    DataContainer(std::string name, std::vector<std::string> data)
        : name_(std::move(name)), data_(std::move(data)) {}
    
    // ✅ 拷贝和移动构造函数
    DataContainer(const DataContainer& other) 
        : name_(other.name_), data_(other.data_) {
        std::cout << "Copy constructor called\n";
    }
    
    DataContainer(DataContainer&& other) noexcept
        : name_(std::move(other.name_)), data_(std::move(other.data_)) {
        std::cout << "Move constructor called\n";
    }
    
    // ✅ 拷贝和移动赋值运算符
    DataContainer& operator=(const DataContainer& other) {
        if (this != &other) {
            name_ = other.name_;
            data_ = other.data_;
        }
        return *this;
    }
    
    DataContainer& operator=(DataContainer&& other) noexcept {
        if (this != &other) {
            name_ = std::move(other.name_);
            data_ = std::move(other.data_);
        }
        return *this;
    }
    
    // ✅ 添加元素的不同方式
    void addData(const std::string& item) {  // 拷贝版本
        data_.push_back(item);
    }
    
    void addData(std::string&& item) {       // 移动版本
        data_.push_back(std::move(item));
    }
    
    // ✅ 完美转发版本
    template<typename T>
    void emplaceData(T&& item) {
        data_.emplace_back(std::forward<T>(item));
    }
    
    // ✅ 就地构造
    template<typename... Args>
    void emplaceString(Args&&... args) {
        data_.emplace_back(std::forward<Args>(args)...);
    }
};

// ✅ 完美转发工厂函数
template<typename T, typename... Args>
auto make_object(Args&&... args) -> std::unique_ptr<T> {
    return std::make_unique<T>(std::forward<Args>(args)...);
}

// 使用示例
void demonstrateMoveSematics() {
    std::vector<std::string> data{"item1", "item2", "item3"};
    
    // 移动构造
    DataContainer container1("container1", std::move(data));
    
    // 拷贝构造
    DataContainer container2 = container1;
    
    // 移动赋值
    DataContainer container3("temp", {});
    container3 = std::move(container1);
    
    // 就地构造
    container3.emplaceString(10, 'x');  // 构造10个'x'的字符串
}

容器和算法优化

cpp
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <numeric>

class OptimizedContainer {
public:
    // ✅ 预分配内存
    void addManyItems(size_t count) {
        items_.reserve(items_.size() + count);  // 避免多次重新分配
        
        for (size_t i = 0; i < count; ++i) {
            items_.emplace_back(generateItem(i));
        }
    }
    
    // ✅ 使用算法而非手写循环
    void processItems() {
        // 并行处理(C++17)
        std::for_each(std::execution::par_unseq, 
                     items_.begin(), items_.end(),
                     [](auto& item) { item.process(); });
        
        // 条件计数
        auto valid_count = std::count_if(items_.begin(), items_.end(),
                                       [](const auto& item) { return item.isValid(); });
        
        // 查找
        auto it = std::find_if(items_.begin(), items_.end(),
                              [](const auto& item) { return item.getId() == target_id_; });
        
        if (it != items_.end()) {
            found_item_ = *it;
        }
    }
    
    // ✅ 范围算法(C++20)
    void modernProcessing() {
        namespace ranges = std::ranges;
        
        // 过滤和变换
        auto valid_ids = items_ 
            | ranges::views::filter([](const auto& item) { return item.isValid(); })
            | ranges::views::transform([](const auto& item) { return item.getId(); });
        
        // 排序
        ranges::sort(items_, [](const auto& a, const auto& b) {
            return a.getPriority() > b.getPriority();
        });
    }
    
    // ✅ 高效的查找结构
    void setupLookup() {
        // 使用unordered_map进行快速查找
        for (const auto& item : items_) {
            id_to_item_[item.getId()] = &item;
        }
    }
    
    const Item* findById(int id) const {
        auto it = id_to_item_.find(id);
        return (it != id_to_item_.end()) ? it->second : nullptr;
    }
    
private:
    std::vector<Item> items_;
    std::unordered_map<int, const Item*> id_to_item_;
    int target_id_ = 0;
    Item found_item_;
    
    Item generateItem(size_t index) {
        return Item{static_cast<int>(index)};
    }
};

🏗️ 设计最佳实践

SOLID原则应用

cpp
// ✅ 单一职责原则 (Single Responsibility Principle)
class UserValidator {
public:
    bool isValidEmail(const std::string& email) const {
        return email.find('@') != std::string::npos;
    }
    
    bool isValidPassword(const std::string& password) const {
        return password.length() >= 8;
    }
};

class UserRepository {
public:
    virtual ~UserRepository() = default;
    virtual bool saveUser(const User& user) = 0;
    virtual std::optional<User> findUser(const std::string& email) = 0;
};

class UserService {
private:
    std::unique_ptr<UserValidator> validator_;
    std::unique_ptr<UserRepository> repository_;
    
public:
    UserService(std::unique_ptr<UserValidator> validator,
               std::unique_ptr<UserRepository> repository)
        : validator_(std::move(validator))
        , repository_(std::move(repository)) {}
    
    bool registerUser(const std::string& email, const std::string& password) {
        if (!validator_->isValidEmail(email) || 
            !validator_->isValidPassword(password)) {
            return false;
        }
        
        User user{email, password};
        return repository_->saveUser(user);
    }
};

// ✅ 开闭原则 (Open/Closed Principle)
class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;
    virtual void draw() const = 0;
};

class Circle : public Shape {
private:
    double radius_;
    
public:
    explicit Circle(double radius) : radius_(radius) {}
    
    double area() const override {
        return 3.14159 * radius_ * radius_;
    }
    
    void draw() const override {
        std::cout << "Drawing circle with radius " << radius_ << std::endl;
    }
};

class ShapeCalculator {
public:
    double totalArea(const std::vector<std::unique_ptr<Shape>>& shapes) const {
        return std::accumulate(shapes.begin(), shapes.end(), 0.0,
                              [](double sum, const auto& shape) {
                                  return sum + shape->area();
                              });
    }
};

// ✅ 依赖注入
class DatabaseConfig {
public:
    virtual ~DatabaseConfig() = default;
    virtual std::string getConnectionString() const = 0;
};

class Database {
private:
    std::shared_ptr<DatabaseConfig> config_;
    
public:
    explicit Database(std::shared_ptr<DatabaseConfig> config)
        : config_(std::move(config)) {}
    
    bool connect() {
        std::string conn_str = config_->getConnectionString();
        // 连接逻辑
        return true;
    }
};

异常安全保证

cpp
#include <vector>
#include <memory>
#include <stdexcept>

class ExceptionSafeContainer {
private:
    std::vector<std::unique_ptr<Resource>> resources_;
    size_t capacity_;
    
public:
    explicit ExceptionSafeContainer(size_t initial_capacity = 10)
        : capacity_(initial_capacity) {
        resources_.reserve(capacity_);
    }
    
    // ✅ 强异常安全保证
    void addResource(std::unique_ptr<Resource> resource) {
        if (!resource) {
            throw std::invalid_argument("Resource cannot be null");
        }
        
        // 如果需要扩容,先检查是否可能失败
        if (resources_.size() >= capacity_) {
            // 创建新的容器,如果失败不会影响原容器
            std::vector<std::unique_ptr<Resource>> new_resources;
            new_resources.reserve(capacity_ * 2);
            
            // 移动现有资源(不会抛异常)
            for (auto& res : resources_) {
                new_resources.push_back(std::move(res));
            }
            
            // 添加新资源
            new_resources.push_back(std::move(resource));
            
            // 原子性更新(不会抛异常)
            resources_ = std::move(new_resources);
            capacity_ *= 2;
        } else {
            // 直接添加(可能抛异常,但不会破坏容器状态)
            resources_.push_back(std::move(resource));
        }
    }
    
    // ✅ 基本异常安全保证
    void processAllResources() {
        size_t processed = 0;
        try {
            for (auto& resource : resources_) {
                if (resource) {
                    resource->process();
                    ++processed;
                }
            }
        } catch (const std::exception& e) {
            // 记录已处理的数量,保证容器仍然有效
            std::cerr << "Processed " << processed << " resources before error: " 
                      << e.what() << std::endl;
            throw;  // 重新抛出异常
        }
    }
    
    // ✅ 无抛出保证
    size_t size() const noexcept {
        return resources_.size();
    }
    
    bool empty() const noexcept {
        return resources_.empty();
    }
    
    void clear() noexcept {
        resources_.clear();
    }
};

// ✅ RAII + 异常安全的事务类
class Transaction {
private:
    bool committed_ = false;
    std::function<void()> rollback_action_;
    
public:
    template<typename RollbackFunc>
    explicit Transaction(RollbackFunc&& rollback)
        : rollback_action_(std::forward<RollbackFunc>(rollback)) {}
    
    ~Transaction() {
        if (!committed_ && rollback_action_) {
            try {
                rollback_action_();
            } catch (...) {
                // 析构函数中不能抛异常
                std::cerr << "Error during rollback" << std::endl;
            }
        }
    }
    
    void commit() noexcept {
        committed_ = true;
    }
    
    Transaction(const Transaction&) = delete;
    Transaction& operator=(const Transaction&) = delete;
};

🧪 测试驱动开发

可测试代码设计

cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>

// ✅ 依赖注入使代码可测试
class EmailService {
public:
    virtual ~EmailService() = default;
    virtual bool sendEmail(const std::string& to, 
                          const std::string& subject,
                          const std::string& body) = 0;
};

class Logger {
public:
    virtual ~Logger() = default;
    virtual void log(const std::string& message) = 0;
};

class NotificationService {
private:
    std::shared_ptr<EmailService> email_service_;
    std::shared_ptr<Logger> logger_;
    
public:
    NotificationService(std::shared_ptr<EmailService> email_service,
                       std::shared_ptr<Logger> logger)
        : email_service_(std::move(email_service))
        , logger_(std::move(logger)) {}
    
    bool sendWelcomeEmail(const std::string& user_email) {
        logger_->log("Sending welcome email to: " + user_email);
        
        bool success = email_service_->sendEmail(
            user_email,
            "Welcome!",
            "Welcome to our service!"
        );
        
        if (success) {
            logger_->log("Welcome email sent successfully");
        } else {
            logger_->log("Failed to send welcome email");
        }
        
        return success;
    }
};

// Mock对象
class MockEmailService : public EmailService {
public:
    MOCK_METHOD(bool, sendEmail, 
                (const std::string& to, const std::string& subject, const std::string& body),
                (override));
};

class MockLogger : public Logger {
public:
    MOCK_METHOD(void, log, (const std::string& message), (override));
};

// 测试
class NotificationServiceTest : public ::testing::Test {
protected:
    void SetUp() override {
        mock_email_service_ = std::make_shared<MockEmailService>();
        mock_logger_ = std::make_shared<MockLogger>();
        service_ = std::make_unique<NotificationService>(mock_email_service_, mock_logger_);
    }
    
    std::shared_ptr<MockEmailService> mock_email_service_;
    std::shared_ptr<MockLogger> mock_logger_;
    std::unique_ptr<NotificationService> service_;
};

TEST_F(NotificationServiceTest, SendWelcomeEmailSuccess) {
    const std::string email = "user@example.com";
    
    EXPECT_CALL(*mock_logger_, log("Sending welcome email to: " + email));
    EXPECT_CALL(*mock_email_service_, sendEmail(email, "Welcome!", "Welcome to our service!"))
        .WillOnce(::testing::Return(true));
    EXPECT_CALL(*mock_logger_, log("Welcome email sent successfully"));
    
    bool result = service_->sendWelcomeEmail(email);
    
    EXPECT_TRUE(result);
}

🔧 现代C++特性使用

类型安全和constexpr

cpp
#include <type_traits>
#include <concepts>

// ✅ 强类型包装器
template<typename T, typename Tag>
class StrongType {
private:
    T value_;
    
public:
    explicit constexpr StrongType(T value) : value_(std::move(value)) {}
    
    constexpr const T& get() const noexcept { return value_; }
    constexpr T& get() noexcept { return value_; }
    
    // 比较运算符
    constexpr bool operator==(const StrongType& other) const noexcept {
        return value_ == other.value_;
    }
    
    constexpr auto operator<=>(const StrongType& other) const noexcept {
        return value_ <=> other.value_;
    }
};

// 类型别名
using UserId = StrongType<int, struct UserIdTag>;
using ProductId = StrongType<int, struct ProductIdTag>;
using Price = StrongType<double, struct PriceTag>;

// ✅ 概念约束(C++20)
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

template<typename T>
concept Container = requires(T container) {
    typename T::value_type;
    typename T::iterator;
    container.begin();
    container.end();
    container.size();
};

// ✅ constexpr函数
constexpr Price calculateTax(Price base_price, double tax_rate) {
    return Price{base_price.get() * (1.0 + tax_rate)};
}

// ✅ if constexpr用于模板特化
template<typename T>
void processValue(const T& value) {
    if constexpr (std::is_arithmetic_v<T>) {
        std::cout << "Processing numeric value: " << value << std::endl;
    } else if constexpr (std::is_same_v<T, std::string>) {
        std::cout << "Processing string: " << value << std::endl;
    } else {
        std::cout << "Processing other type" << std::endl;
    }
}

// 使用示例
void demonstrateModernCpp() {
    UserId user_id{12345};
    ProductId product_id{67890};
    
    // 编译时错误:不能比较不同类型
    // bool same = (user_id == product_id);  // 编译错误
    
    Price base_price{100.0};
    constexpr double tax_rate = 0.1;
    
    // constexpr计算
    constexpr auto final_price = calculateTax(Price{100.0}, 0.1);
    
    processValue(42);
    processValue(std::string{"Hello"});
    processValue(user_id);
}

总结

核心最佳实践

  • RAII: 资源管理的黄金法则
  • 智能指针: 自动内存管理
  • 移动语义: 性能优化的关键
  • 异常安全: 保证程序健壮性
  • 依赖注入: 提高代码可测试性

性能最佳实践

  • 避免不必要拷贝: 使用引用和移动语义
  • 预分配内存: 容器reserve操作
  • 算法优于循环: 使用STL算法
  • constexpr: 编译时计算
  • 缓存友好: 考虑内存访问模式

设计最佳实践

  • SOLID原则: 良好的面向对象设计
  • 组合优于继承: 灵活的代码结构
  • 接口隔离: 小而专一的接口
  • 强类型: 编译时类型安全
  • 概念约束: 清晰的模板接口

代码质量最佳实践

  • TDD: 测试驱动开发
  • 代码审查: 团队知识共享
  • 静态分析: 工具辅助质量检查
  • 文档化: 清晰的代码文档
  • 持续重构: 保持代码整洁

现代C++特性

  • auto: 类型推导
  • 范围for: 简洁的迭代
  • lambda: 函数式编程
  • 智能指针: 现代内存管理
  • 概念: 模板约束(C++20)

避免的反模式

  • 裸指针: 除非必要避免使用
  • 全局变量: 破坏封装性
  • 深度继承: 复杂的类层次
  • premature optimization: 过早优化
  • 复杂模板: 难以理解和维护

C++最佳实践是经验的结晶,遵循这些实践能显著提升代码质量、性能和可维护性。随着C++标准的发展,最佳实践也在不断演进,保持学习和更新是C++开发者的必修课。

本站内容仅供学习和研究使用。