08 October 2022

C++ 核心指南目录

“Prefer default constructors to be simple and non-throwing”

理由

无需额外的、会报错的操作,就能设定默认值,可以简化错误处理的过程和移动操作的推演。

错误例子

template<typename T>
// elem points to space-elem element allocated using new
class Vector0 {
public:
    Vector0() :Vector0{0} {}
    Vector0(int n) :elem{new T[n]}, space{elem + n}, last{elem} {}
    // ...
private:
    own<T*> elem;
    T* space;
    T* last;
};

这个类定义看起来挺不错,但是给 Vector0 设定空值的时候,也可能由于内存分配出错。另外,用 {new T[0], 0, 0} 这样的方式来表示默认 Vector 看起来很浪费。比如, Vector0<int> v[100] 会导致 100 次内存分配。

例子

template<typename T>
// elem is nullptr or elem points to space-elem element allocated using new
class Vector1 {
public:
    // sets the representation to {nullptr, nullptr, nullptr}; doesn't throw
    Vector1() noexcept {}
    Vector1(int n) :elem{new T[n]}, space{elem + n}, last{elem} {}
    // ...
private:
    own<T*> elem {};
    T* space {};
    T* last {};
};

用 {nullptr, nullptr, nullptr} 表示 Vector1{} 更节省资源,而且这种特殊情况意味着运行时检查,防止出错。如果检测到错误,把 Vector1 设定为空比较简单。

强化

  • 标记会抛出异常的构造函数