为什么为具有非平凡析构函数的类声明constrexpr构造函数(例如unique_ptr,std :: variant)

时间:2015-06-10 19:57:06

标签: c++ c++14 constexpr c++17

据我所知(至少对c++14而言),如果析构函数不是微不足道的(隐式生成或constexpr),则析构函数不能为=default。为具有非平凡析构函数的结构声明constexpr构造函数有什么意义?

struct X {
  int a_;

  constexpr X(int a) : a_{a} {}

  // constexpr ~X(){}; // Error dtor cannot be marked constexpr
  // ~X(){}; // causes  error at y declaration: temporary of non-literal type ‘X’
             // in a constant expression .
};

template <int N> struct Y {};

int main() {
  Y<X{3}.a_> y; // OK only if the destructor is trivial
  (void)y;
}
// tested with c++14 g++-5.1.0 and clang++ 3.5.0

例如std::unique_ptr有一些constructors constexpr(默认值和nullptr_t),即使析构函数明显是明确定义的(如果对象是明确的话,它确实没有效果) nullptr,但这并不意味着它仍然有一个显式定义的析构函数,以检查对象是否处于空状态,正如我所见,即使是一个空的析构函数也不允许要在编译常量表达式中使用的对象)

另一个示例是std::variant的提案:它几乎包含所有构造函数constexpr,尽管析构函数具有签名~variant()并且必须call get<T_j> *this).T_j::~T_j() with j being index().

我错过了什么?

1 个答案:

答案 0 :(得分:16)

constexpr构造函数可用于常量初始化,作为静态初始化的一种形式,保证在任何动态初始化发生之前发生。

例如,给定全局std::mutex

std::mutex mutex;

在符合要求的实现中(读取:不是MSVC),其他对象的构造函数可以安全地锁定和解锁mutex,因为std::mutex的构造函数是constexpr