一、C++惯用法(Idioms)

C++有一些区别于其他语言的独特惯用法,这些是经验丰富的C++开发者总结的最佳实践,理解它们是写出地道C++代码的前提。

1.1 Pimpl(Pointer to Implementation)

// Pimpl:将实现细节隐藏到编译防火墙后面
// 优点:减少编译依赖、降低头文件变更影响

// widget.h(公开头文件)
#pragma once
#include 

class Widget {
public:
    Widget();                      // 构造函数
    ~Widget();                     // 必须完整定义(unique_ptr需要)
    Widget(Widget&&);              // 移动构造
    Widget& operator=(Widget&&);   // 移动赋值

    void draw();
    void resize(int w, int h);

private:
    // 指向实现类的指针,不在头文件中包含任何依赖
    struct Impl;
    std::unique_ptr pImpl_;  // unique_ptr支持前向声明
};

// widget.cpp(实现文件)
#include "widget.h"
#include "gizmo.h"     // 仅在.cpp中可见,头文件不暴露
#include "renderer.h"   // 头文件变更不影响widget.h的用户

struct Widget::Impl {
    Gizmo gizmo;
    Renderer renderer;
    int width_ = 0;
    int height_ = 0;
};

Widget::Widget() : pImpl_(std::make_unique()) {}
Widget::~Widget() = default;  // unique_ptr完整类型已知
Widget::Widget(Widget&&) = default;
Widget& Widget::operator=(Widget&&) = default;

void Widget::draw() { pImpl_->renderer.draw(pImpl_->gizmo); }
void Widget::resize(int w, int h) {
    pImpl_->width_ = w;
    pImpl_->height_ = h;
}

// 效果:
// - widget.h 不再依赖 gizmo.h / renderer.h
// - 修改实现不影响用户代码重新编译
// - 编译时间可减少50-80%(对大项目显著)

二、CRTP与Mixin模式

2.1 CRTP(Curiously Recurring Template Pattern)

// CRTP:模板继承,编译期多态(无虚函数开销)
template
class Base {
public:
    void interface() {
        // 在基类中调用派生类的实现
        static_cast(this)->implementation();
    }

    // 策略:基类提供默认实现
    void default_behavior() {
        // ...
    }
};

class Derived : public Base {
public:
    void implementation() {
        // 派生类实现
    }
};

// 应用场景①:静态多态(替代虚函数)
template
void process(T& obj) {
    obj.execute();  // 编译期绑定,无虚表查找
}

// 应用场景②:计数器Mixin
template
class Counted : public T {
    inline static int instance_count = 0;
public:
    Counted() { ++instance_count; }
    ~Counted() { --instance_count; }
    static int count() { return instance_count; }
};

class MyClass : public Counted {};
// MyClass对象数量 → MyClass::count()

// CRTP vs 虚函数:
// CRTP优点:无虚表、inline内联可能、内联优化更好
// CRTP缺点:编译期绑定、不支持运行时多态(无基类指针)

2.2 Tag Dispatch与Type Dispatch

// Tag Dispatch:基于类型标签的编译期分发
// 用于在模板函数中区分不同类型的处理策略

#include 

// 为特定类型提供优化实现
template
void append_one(Container& c) {
    // 通过类型标签分派到不同实现
    append_one_impl(c, std::is_integral{});
}

// true_type分派路径
template
void append_one_impl(Container& c, std::true_type) {
    // 整数类型:++操作
    c.push_back(typename Container::value_type(1));
}

// false_type分派路径
template
void append_one_impl(Container& c, std::false_type) {
    // 非整数类型:用默认值
    c.push_back(typename Container::value_type{});
}

三、GoF设计模式在C++中的实现

3.1 单例模式:双重检查锁定

// C++11线程安全单例(双重检查锁定 + memory_order)
class Singleton {
public:
    static Singleton* get_instance() {
        Singleton* p = instance.load(std::memory_order_acquire);
        if (p == nullptr) {
            std::lock_guard lock(mtx_);
            p = instance.load(std::memory_order_relaxed);
            if (p == nullptr) {
                p = new Singleton;
                instance.store(p, std::memory_order_release);
            }
        }
        return p;
    }

private:
    static std::atomic instance;
    static std::mutex mtx_;
    Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

// C++17起:更简洁的局部静态变量方案
// (C++11保证局部静态变量线程安全初始化)
class SingletonSimple {
public:
    static SingletonSimple& get() {
        static SingletonSimple instance;  // 线程安全初始化
        return instance;
    }

private:
    SingletonSimple() = default;
};

// 最佳实践:优先使用局部静态变量(更简洁+编译器优化)

3.2 工厂模式:模板工厂

// 模板工厂:编译期注册,运行时创建
#include 
#include 

class Product {
public:
    virtual ~Product() = default;
    virtual std::string name() const = 0;
};

template
classRegistrar {
    // 辅助类:构造函数中注册创建函数
public:
    explicit ClassRegistrar(const std::string& name) {
        Factory::instance().register_(name, []() -> Product* {
            return new ConcreteProduct;
        });
    }
};

class Factory {
public:
    static Factory& instance();

    void register_(const std::string& name, std::function creator) {
        creators_[name] = std::move(creator);
    }

    Product* create(const std::string& name) const {
        auto it = creators_.find(name);
        return (it != creators_.end()) ? it->second() : nullptr;
    }

private:
    std::map> creators_;
};

// 使用:
// product.h
class ConcreteProductA : public Product {
public:
    std::string name() const override { return "ProductA"; }
};
// product.cpp
static ClassRegistrar reg_a("ProductA");

四、Scope Guard与RAII扩展

// Scope Guard:确保退出作用域时执行清理
// 用途:数据库事务回滚、文件句柄关闭、解锁互斥锁

class ScopeGuard {
public:
    explicit ScopeGuard(std::function fn) : fn_(fn), dismissed_(false) {}
    ~ScopeGuard() { if (!dismissed_) fn_(); }

    void dismiss() { dismissed_ = true; }

private:
    std::function fn_;
    bool dismissed_;
};

// C++23已经提供std::scope_exit:
#include 

void process() {
    auto guard = std::scope_exit([]{ unlock(); });

    if (error_condition) {
        return;  // 自动unlock
    }

    guard.release();  // 取消自动执行
    commit();         // 手动提交
}

// 实用场景:
// ① 数据库事务(回滚)
auto conn = db.connect();
auto tx = conn.begin();
auto rollback = std::scope_exit([&] { tx.rollback(); });

do_work();
tx.commit();
rollback.release();

// ② 临时改变locale
auto locale_guard = std::scope_exit([old = std::locale::global(std::locale::classic())] {});