我应该定义默认构造函数吗?

11

所以我们正在进行一些同行评审,这里出现了一些小分歧,

即使它什么也不做,应该定义默认构造函数呢?还是应该让编译器定义它呢?

到目前为止,双方都没有找到任何重大的优缺点。每种风格的利弊如何,哪种被认为更“清洁”?


@nosid 有关紧要吗?但是对于这个问题,使用C++11。 - user1708860
定义它有单一的优点吗?两个缺点是:需要维护更多的代码并且容易混淆,而且在C++03中你实际上可能会出错。 - juanchopanza
3
在C++11中,您可以在构造函数中使用“=default”。 - Étienne
1
让我们这样说吧:带有不必要的用户提供默认构造函数的代码很难通过我参与的任何代码审查 :-) - juanchopanza
1
询问具体的优缺点使得这个问题成为一个有效的、非基于个人观点的问题。 - Adrian McCarthy
显示剩余4条评论
2个回答

16
这个问题可能会被归类为“主观性较强”,但我可以给你一些客观的考虑点:
  • 如果你定义默认构造函数,后来有人添加带参数的构造函数,却忘记同时添加无参构造函数,那么默认构造函数将消失,这可能会导致现有代码出现错误。明确定义它可以确保即使有人后来添加了重载构造函数,无参构造函数仍然存在。

  • 如果在头文件中声明构造函数,并在一个.cc/.cpp文件中定义它,则实现以后可以通过重新链接相关代码进行修改。而在之后声明构造函数会对头文件产生影响,需要重新编译相关代码。

    • 空的、外部的默认构造函数仍然需要调用,会产生一定的运行时间成本,而使用编译器隐含提供的默认构造函数时,编译器可以看到不需要进行任何操作并避免调用。
  • 明确定义需要更多的键入工作,并且会导致更多的代码行数。这会带来小但非零的成本(输入时间和代码读者阅读的时间)。

  • 显式定义会使类不再是聚合类=default in C++11,除非你在C++11中使用=default

是的,这些观点是相互矛盾的。我认为你会发现占主导地位的观点不要明确定义它,但是就语言而言,没有正确或错误的方法。(除非需要将类型作为聚合体)


如果您不能确定用户提供的构造函数与编译器生成的构造函数相同,那么您就不能说它们没有性能/行为差异。 - juanchopanza
2
@user2079303 用户声明不等于用户定义。您可以拥有显式默认构造函数,它仍然是一个聚合体。 - user1508519
@juanchopanza 抱歉,我不明白你的观点;在什么情况下,您会被要求提供初始化列表,而编译器可以自动完成呢?如果内置类型需要构造函数参数,则编译器无法生成默认构造函数。 - TypeIA
1
@juanchopanza 我明白了,但我认为这并不是一个“什么也不做”的构造函数。它通过初始化 Bar::a 来完成某些操作。也许我们可以规定在本回答的范围内,构造函数具有空函数体和没有初始化列表? - TypeIA
1
@user1708860:因为1)这本身不是一个非常完整的答案,2)我不想抄袭其他回答中提出的观点来组成一个完整的答案,3)这个答案应该更新以避免误导读者。 - Tony Delroy
显示剩余11条评论

2

没有任何用户构造函数

只有当您的默认构造函数执行与编译器生成的构造函数不同的操作时,才应该实现自己的默认构造函数。

如果您想给读者一个提示,您可以在C++11中用= default替换实现。

struct MyObject {
    // only members that the compiler initializes fine 
    std::vector<int> data_;
    MyObject() = default;
};

或者,如果您不想那么冗长(或在C++11之前):

struct MyObject {
    // only members that the compiler initializes fine 
    std::vector<int> data_;
};

与其他用户构造函数一同使用

如果您提供任何其他构造函数,编译器将不会生成默认的构造函数。在这种情况下,您应该只在语义上有必要时提供默认构造函数,而不是因为它很“好”才提供 :-)

优缺点

显式提供一个不必要的默认构造函数

  • (-) 多余的代码总是不好的。
  • (o) 除非通过提供默认构造函数(= default)获得更清晰的源代码,超过了其带来的额外代码量。
  • (-) 由编译器生成的默认构造函数通常是最优的。
  • (-) 如果您开始提供一个不必要的成员(“不必要”,因为它会被生成),您最终需要定义所有自动生成的构造函数,即 默认构造函数、析构函数、复制、移动、赋值和移动赋值。您真的不想走到那一步。
  • (-) 您是否知道是否应该使用 noexcept 标记默认构造函数?编译器通常会知道。不要浪费您的大脑能量,让编译器帮助您。

我真的看不出有任何明显的(+),但这只是我的个人看法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接