Skip to content

C++ idioms

// TODO 持续补充记录。

一些 C++ 编程惯用技巧。

《More C++ Idioms》

https://github.com/utilForever/CppIdioms

https://github.com/liuzengh/CppIdioms

RAII: Resource Acquistion is Initialization

RAII 的核心思想是"资源的获取就是初始化的过程"。 这一理念主张,资源的生命周期应该由对象的生命周期来管理。具体来说,就是对象通过构造函数获取资源,在析构函数里释放资源。

应用场景:

  • 智能指针

  • 句柄管理

  • 互斥锁,xxx_guard (lock_guard, thread_guard)

  • and more...

注意事项:

  • 禁止拷贝(Non-Copyable)

  • 资源所有权的转移

  • 对底层资源使用引用计数法

Pimpl: Pointer to Implementation

又叫编译防火墙,其核心思想是将类的实现细节封装到一个独立的类中,通过指针引用这个实现类,实现接口和实现的分离。

应用场景:

  • 在 Qt 中大量使用:d-pointer,q-pointer,一般XXPrivate,XXData都是impl,比如QWidget 中有指向 QWidgetPrivate 的pimpl指针;

  • 在编写动态库时,将类的实现放置于XXImpl中。

好处/优势:

信息隔离、二进制兼容性、实现细节的封装。

CRTP: Curious Recurring Template Pattern

奇异递归,一种实现静态多态的C++模板编程技巧,简单来说就是基类是类模板,派生类在继承该基类时,将自身作为模板参数传递给基类

cpp
template<class DerivedT>
class Based {
public:
    virtual ~Based() {}
    void interface() {
        static_cast<DerivedT*>(this)->implementation();
    }
    void implementation() {
        std::cout << "Default implementation in Base \n";
    }
};

class Derived: public Based<Derived> {
public:
    void implementation() {
        std::cout << "Custom implementation in Derived \n";
    }
};   // ...
};

应用场景:

  • std::enable_shared_from_this

  • 多态拷贝构造

  • 多态链式编程

好处:

  • 静态多态发生在编译时,而动态多态发生在运行时,由此省去动态绑定、查询虚函数表带来得开销。

Erase-Remove

删除容器元素的同时缩小容器大小。std::remove 不会删除容器中的元素,只是将元素移动到容器的最后。这是因为std::remove使用的是forward iterator,而一般 forward iterator迭代器是无法删除容器中的元素的。

应用/实现:

  • std::remove 将“unused”的元素移动至容器末尾,并返回一个指向“unused“元素范围的开始;

  • 容器的成员函数erase()可以删除容器特定范围内容的元素;

cpp
template<typename T>
inline void remove_erase(std::vector<T> &v, const T &item) {
    v.erase(std::remove(v.begin(), v.end(), item), v.end());
}

Non-Copyable/Non-Moveable

用于防止对象被复制,例如文件句柄、网络Socket等,使用该惯例能够避免如内存泄漏或多次释放的问题。

cpp
class NonCopyable{
protected:
  NonCopyable () {}
  ~NonCopyable () {} /// Protected non-virtual destructor
  NonCopyable (const NonCopyable &) = delete;
  NonCopyable& operator= (const NonCopyable &) = delete;
};

class CantCopy : private NonCopyable
{};

实现:

  • 删除拷贝构造函数和拷贝复制运算符重载函数

Copy-and-Swap

用于实现拷贝赋值操作符,利用拷贝构造函数和交换操作,实现安全、高效且自我赋值安全的赋值运算符。

应用场景:

  • 构造函数,拷贝构造函数,移动构造函数,拷贝赋值运算符重载函数,移动赋值运算符重载函数

实现:

  • 拷贝构造函数(Copy Constructor):定义一个拷贝构造函数,用于创建对象的深拷贝

  • 实现交换操作(Swap Operation):定义一个交换操作,用于交换两个对象的内容

  • 赋值操作符(Assignment Operator):利用拷贝构造函数和交换操作,实现赋值操作符

Copy-on-Write

如果多个对象或变量共享相同的数据,那么它们可以共享同一份数据,而不是为每个对象创建独立的数据副本。

应用场景:

  • Qt 中的 QString

  • 高并发读操作,写操作相对较少的场景

  • 并发容器

实现原理

  • 浅拷贝 + 引用计数

    当只是进行读操作时,就只进行浅拷贝,如果写操作时,再进行深拷贝,如果写操作时,再进行深拷贝。

好处:

  • 内存效率提升

  • 性能优化

  • 减少非必要的内存拷贝

Type Erasure

// TODO 类型擦除

Mixin

// TODO