如何在C ++中使用“默认构造函数”

时间:2015-12-13 00:30:33

标签: c++ default-constructor

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

为所有类编写默认构造函数是一个好主意吗?如果您的类没有默认构造函数,那么STL的某些部分是否不起作用?

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

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

    1. 添加额外的字段/逻辑/方法来检查字段是否已初始化并依赖于该字段(想想类似于unique_ptr的“重置”方法)。
    2. 人们如何在现实世界中解决这样的问题?

3 个答案:

答案 0 :(得分:2)

如果数据类型没有默认构造函数,那么就不要写一个。

(STL已经死了,但我认为你的意思是标准库。)即使包含的类型没有默认构造函数,大多数标准库容器也能正常工作。一些值得注意的问题:

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

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

答案 1 :(得分:1)

  

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

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

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

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

对于这样的类型,你真的应该定义一个默认的构造函数。

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

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

对于这些类型,是否定义默认构造函数是一种权衡。这样做没有坏处,但会使您的类型稍微复杂一些。如果它是在库中找到的公共类型,那么它可能是值得的。如果你打算实现一个移动构造函数(和赋值运算符),你也可以很好地定义默认构造函数,以便在一个可以通过远离它来到达的状态下构造对象。

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

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

不要为这些类型创建一个人为的“null”状态,只是为了使它们可以默认构造。这样做会使代码复杂化并迫使您在没有人为状态的情况下提供不太有用的类不变量。如果某人确实需要这种额外的状态,他们可以轻松使用optional<T>,但反过来是不可能的。

  

如果您的类没有默认构造函数,那么STL的某些部分是否不起作用?

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

答案 2 :(得分:0)

  

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

没有。有时对象的默认值没有任何意义。

  

如果您的类没有默认构造函数,那么STL的某些部分是否不起作用?

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