具有默认值的单个参数构造函数是否与默认构造函数相同?

Is a single argument constructor with a default value the same as a default constructor?

本文关键字:构造函数 默认 是否 默认值 单个 参数      更新时间:2023-10-16

>特别是在自动调用基类构造函数的上下文中:具有默认值的基类的单个参数构造函数的处理方式是否与默认构造函数(没有参数的构造函数(相同(例如,如果未另行指定,则自动调用(?

struct base {
base(int value = 42) {}
};
struct derived : public base {
derived() {} // automatic call to base::base(int) ?
};

编辑:以下内容与问题无关,这只是我是如何想到这一点的。下面的代码甚至没有显示我一直看到的崩溃。有关实际示例,请参见下文。

考虑一下:

#include <sstream>
// C++98, std::ostringstream(ios_base::openmode mode = ios_base::out) available
struct OhNo : public std::ostringstream {
OhNo() {
}
void Crash() const {
this->str();
}
};
// later: OhNo f; f.Crash();

std::ostringstream(在 C++11 之前(没有无参数构造函数。只有一个参数和一个默认值。上面的OhNo不调用其基类的构造函数。(是的,确实如此(AFAIK 如果存在无参数构造函数可用,则会自动调用基类构造函数。

GCC 5.4.0 编译得很好,但后来出现了段错误(由于未初始化的基类另一个问题(。 Clang 7.0.0 也可以很好地编译,并且运行代码也没有问题。

谁是对的?这里是否需要手动调用基类构造函数?答:不可以!

受影响的代码:单元测试++MemoryOutStream

相关问题:https://github.com/unittest-cpp/unittest-cpp/issues/174


好吧,我不知道发生了什么。下面的反汇编显示调用了基构造函数。所以答案很可能是"是"。对于任何感兴趣的人,以下是重现这种非常奇怪的行为的方法:

#include "UnitTest++.h"
volatile double A() { return 2; }
TEST(Crash) {
CHECK_CLOSE(1,A(),0.1);
}
int main()
{
int exit_code = 0;
exit_code = UnitTest::RunAllTests();
return exit_code;
}

使用 g++ 编译 libunittest++.a 及其标头(例如来自 https://packages.ubuntu.com/xenial/amd64/libunittest++-dev/download(。

正常运行:

test.cc:5: error: Failure in Crash: Unhandled exception: Crash!
FAILURE: 1 out of 1 tests failed (1 failures).
Test time: 0.00 seconds.

在 gdb 中运行它:

(gdb) catch throw
Catchpoint 1 (throw)
(gdb) run
Starting program: /home/musteresel/huh/libunittest++-dev_1.4.0-3_amd64/data/usr/lib/a.out 
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f205a0 in std::string::assign(std::string const&) () from /nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib/lib/libstdc++.so.6
(gdb) bt
#0  0x00007ffff7f205a0 in std::string::assign(std::string const&) () from /nix/store/hlnxw4k6931bachvg5sv0cyaissimswb-gcc-7.4.0-lib/lib/libstdc++.so.6
#1  0x0000000000403a7a in UnitTest::MemoryOutStream::GetText() const ()
#2  0x0000000000402871 in UnitTest::CheckClose<int, double, double> (results=..., expected=@0x7fffffffbabc: 1, actual=@0x7fffffffbac0: 2, 
tolerance=@0x7fffffffbac8: 0.10000000000000001, details=...) at ../include/unittest++/Checks.h:53
#3  0x0000000000402483 in TestCrash::RunImpl (this=0x408060 <testCrashInstance>) at test.cc:6
#4  0x0000000000402bc2 in void UnitTest::ExecuteTest<UnitTest::Test>(UnitTest::Test&, UnitTest::TestDetails const&) ()
#5  0x0000000000403255 in UnitTest::TestRunner::RunTest(UnitTest::TestResults*, UnitTest::Test*, int) const ()
#6  0x0000000000403683 in UnitTest::RunAllTests() ()
#7  0x0000000000402514 in main () at test.cc:14
(gdb) 

反汇编 -清楚地表明正在调用构造函数:

# in UnitTest::CheckClose<int, double, double>
4027cb:       e8 e2 fd ff ff          callq  4025b2 <UnitTest::MemoryOutStream::MemoryOutStream()>
# in UnitTest::MemoryOutStream::MemoryOutStream()
4025eb:       e8 60 fa ff ff          callq  402050 <std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::basic_ostringstream(std::_Ios_Openmode)@plt>

摘自 ISO/IEC 14882:1998(E( [class.ctor]/5

X的默认构造函数是类X的构造函数,无需参数即可调用。

默认构造函数可以具有参数,只要它们都具有默认参数,因此可以在没有参数的情况下调用构造函数。

如果未在构造函数的初始值设定项列表中为基类显式指定mem 初始值设定项,则将通过其默认构造函数初始化基类。

std::basic_ostringstreamC++98 中已经有一个默认构造函数(一个具有一个具有默认参数的参数的构造函数(。如果你仔细观察,你会发现你链接的cpp偏好页面证实了这一点......

我想先解决问题的动机,然后再讨论问题本身。激励人的例子是

std::ostringstream(在 C++11 之前(没有无参数构造函数。只有一个参数和一个默认值。

虽然这是真的,但这不是要关注的变化。在 C++11 之前,有一个默认构造函数。它的签名实际上是(不是字面意思(

explicit basic_ostringstream();

从 C++11 开始,签名变成了

basic_ostringstream();

注意到区别了吗?默认构造函数不再标记为explicit。这是所期望的改变。还希望将openmode作为其唯一参数的构造函数保持explicit。因此,有必要增加构造函数声明的数量。(另请参阅您链接到的页面上列出的缺陷报告。

具有默认值的单个参数构造函数是否与默认构造函数相同?

不是真的,因为前者可以用参数调用。 :P但是对于这个问题,我相信你打算,是的,所有参数都有默认值的构造函数确实充当该类的默认构造函数。

谁是对的?这里是否需要手动调用基类构造函数?

崩溃往往意味着你有未定义的行为。至少,我不记得标准中要求崩溃作为所需行为的任何部分。:)当行为未定义时,没有错误的行为。(每个人都是对的。