如何在C++"default constructor"

How to "default constructor" in C++

本文关键字:default constructor C++      更新时间:2023-10-16

我最近遇到了一个问题,因为我是一个自学成才C++程序员,我真的很想知道现实世界中的专业人士是如何解决它的。

为所有类编写默认构造函数是个好主意吗?如果您的类没有默认构造函数,STL 的某些部分

是否不起作用?

如果是这样,那么如何编写一个做明智事情的默认构造函数?也就是说,如果根本没有合理的默认值,如何为我的私有成员分配默认值?我只能想到两个解决方案:

  1. 对每个成员使用指针(或unique_ptrs(,这样 nullptr 表示字段未初始化。

  1. 添加额外的字段/逻辑/方法来执行检查字段是否已初始化的工作并依赖它(想想有点像unique_ptr的"重置"方法(。

人们如何在现实世界中解决这样的问题?

如果您的数据类型具有默认构造函数没有意义,则不要编写一个。

(STL早已死了,但我猜你的意思是标准库。 大多数标准库容器都可以正常工作,即使包含的类型没有默认构造函数也是如此。 一些值得注意的陷阱:

  • std::vector<T>::resize(n)要求T具有默认构造函数。 但是如果没有,您可以使用eraseinsert代替。

  • std::map<K,V>::operator[]std::unordered_map<K,V>::operator[]要求V具有默认构造函数。 但是如果没有,您可以使用findinsert代替。

为所有类编写默认构造函数是个好主意吗?

不。如果您的类型没有合理的"默认值",则不应编写默认构造函数。这样做会违反最小意外原则。

也就是说,许多类型确实具有合理的默认值。

  • 数字零(更一般地说:中性元素(
  • 空字符串
  • 一个空列表
  • A 0 × 0 矩阵
  • 时区 UTC &pm; 00:00

对于此类类型,您确实应该定义一个默认构造函数。

其他类型没有自然默认值,但具有"空"状态,可以通过执行某些操作来达到该状态。默认构造这样的对象以具有该状态是明智的。

  • 与每个操作失败的任何源/接收器断开连接的 I/O 流(可以通过到达文件末尾或遇到 I/O 错误来访问(
  • 没有锁的
  • 锁护罩(可以通过释放锁来到达(
  • 不拥有对象的智能指针(可以通过释放托管对象来访问(

对于这些类型,是否需要定义默认构造函数。这样做没有坏处,但会使您的类型稍微复杂一些。如果它是在库中找到的公共类型,那么它可能值得麻烦。如果你无论如何都要实现移动构造函数(和赋值运算符(,你同样可以很好地定义默认构造函数,以构造一个状态的对象,该状态可以通过移开它来达到。

对于其他类型,您无法定义合理的默认值。

  • 一周中的某一天
  • 婴儿的名字

不要为这些类型发明人为的"null"状态,只是为了让它们默认可构造。这样做会使代码复杂化,并迫使您在没有这种人工状态的情况下提供不太有用的类不变量。如果有人真的需要这种额外的状态,他们可以很容易地使用optional<T>但反过来是不可能的。

如果您的类没有默认构造函数,STL 的某些部分

是否不起作用?

是的。 std::vector::resize可能是最突出的例子。但不要担心这些。如果类型没有合理的默认值,则执行该操作也没有意义。这不是你类型的错。这是您尝试建模的概念的性质所固有的。

为所有类编写默认构造函数是个好主意吗?

不。有时,为对象设置默认值是没有意义的。

如果您的类没有默认构造函数,STL 的某些部分

是否不起作用?

有些部分需要 DefaultConstructible 对象。并且有一些方法可以规避它(重载,它需要一个对象来使用而不是默认构造(。