具有默认值的单参数构造函数是否与默认构造函数相同?
Is a single argument constructor with a default value the same as a default constructor?
特别是在自动调用基础 class 构造函数的上下文中:是基础 class 的单参数构造函数,具有默认值,处理方式相同(例如,如果未指定则自动调用否则)作为默认构造函数(不带参数的构造函数)?
struct base {
base(int value = 42) {}
};
struct derived : public base {
derived() {} // automatic call to base::base(int) ?
};
edit:以下内容与问题无关,这只是我遇到这个问题的方式。以下代码甚至没有出现我所看到的崩溃。请参阅下面的实际示例。
考虑一下:
#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 之前)didn't have a no-argument constructor。只有一个参数和一个默认值。 上面的 OhNo
没有调用其基础 class. 的构造函数(是的)据我所知,基础 class 构造函数被自动调用 如果 有一个 no-argument 构造函数可用。
GCC 5.4.0 可以很好地编译,但后来会出现段错误(由于 未初始化的基 class 另一个问题) .
Clang 7.0.0 也可以很好地编译并运行代码也没有问题。
谁说得对?这里需要手动调用baseclass构造函数吗? 回答:没有!
受影响代码:UnitTest++ MemoryOutStream
class
相关问题:https://github.com/unittest-cpp/unittest-cpp/issues/174
好的,我不知道发生了什么。下面的反汇编显示调用了基本构造函数。所以答案很可能是 "YES". 对于任何感兴趣的人,这里是重现这种非常奇怪的行为的方法:
#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;
}
针对 libunittest++.a 使用 g++ 编译,它是 headers(例如来自 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
A default constructor for a class X
is a constructor of class X
that can be called without an argument.
默认构造函数可以有参数,只要它们都有默认参数,因此可以不带参数调用构造函数。
如果您没有在构造函数的初始化列表中为基 class 显式指定 mem-initializer,则基 class 将被初始化通过它的默认构造函数。
std::basic_ostringstream
在 C++98 中已经有一个默认构造函数(一个带有一个参数的构造函数,它有一个默认参数)。如果您仔细观察,您会发现您链接的 cppreference 页面证实了这一点……
我想在问题本身之前解决问题的动机。激励的例子是
std::ostringstream
(prior to C++11) didn't have a no-argument constructor. Just one with a single argument and a default value.
尽管如此,但这不是要关注的变化。在 C++11 之前,有一个默认构造函数。它的签名是有效的(不是字面上的)
explicit basic_ostringstream();
从C++11开始,签名变成了
basic_ostringstream();
注意区别了吗?默认构造函数不再被标记 explicit
。这是期望的改变。还希望将 openmode
作为其唯一参数的构造函数保持 explicit
。因此,需要增加构造函数声明的数量。 (另请参阅您链接到的页面上列出的缺陷报告。)
Is a single argument constructor with a default value the same as a default constructor?
不是真的,因为前者可以用参数调用。 :P 但是对于我相信你想要的问题,是的,所有参数都具有默认值的构造函数确实用作 class.
的默认构造函数
Who's right? Is it necessary to manually call the base class constructor here?
崩溃往往意味着您有未定义的行为。至少,我不记得标准中要求将崩溃作为必需行为的任何部分。 :) 当行为未定义时,没有错误行为。 (大家都说得对。)
特别是在自动调用基础 class 构造函数的上下文中:是基础 class 的单参数构造函数,具有默认值,处理方式相同(例如,如果未指定则自动调用否则)作为默认构造函数(不带参数的构造函数)?
struct base {
base(int value = 42) {}
};
struct derived : public base {
derived() {} // automatic call to base::base(int) ?
};
edit:以下内容与问题无关,这只是我遇到这个问题的方式。以下代码甚至没有出现我所看到的崩溃。请参阅下面的实际示例。
考虑一下:
#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 之前)didn't have a no-argument constructor。只有一个参数和一个默认值。 上面的 的构造函数(是的)据我所知,基础 class 构造函数被自动调用 如果 有一个 no-argument 构造函数可用。OhNo
没有调用其基础 class.
GCC 5.4.0 可以很好地编译,但后来会出现段错误(由于 未初始化的基 class 另一个问题) .
Clang 7.0.0 也可以很好地编译并运行代码也没有问题。
谁说得对?这里需要手动调用baseclass构造函数吗? 回答:没有!
受影响代码:UnitTest++ MemoryOutStream
class
相关问题:https://github.com/unittest-cpp/unittest-cpp/issues/174
好的,我不知道发生了什么。下面的反汇编显示调用了基本构造函数。所以答案很可能是 "YES". 对于任何感兴趣的人,这里是重现这种非常奇怪的行为的方法:
#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;
}
针对 libunittest++.a 使用 g++ 编译,它是 headers(例如来自 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
A default constructor for a class
X
is a constructor of classX
that can be called without an argument.
默认构造函数可以有参数,只要它们都有默认参数,因此可以不带参数调用构造函数。
如果您没有在构造函数的初始化列表中为基 class 显式指定 mem-initializer,则基 class 将被初始化通过它的默认构造函数。
std::basic_ostringstream
在 C++98 中已经有一个默认构造函数(一个带有一个参数的构造函数,它有一个默认参数)。如果您仔细观察,您会发现您链接的 cppreference 页面证实了这一点……
我想在问题本身之前解决问题的动机。激励的例子是
std::ostringstream
(prior to C++11) didn't have a no-argument constructor. Just one with a single argument and a default value.
尽管如此,但这不是要关注的变化。在 C++11 之前,有一个默认构造函数。它的签名是有效的(不是字面上的)
explicit basic_ostringstream();
从C++11开始,签名变成了
basic_ostringstream();
注意区别了吗?默认构造函数不再被标记 explicit
。这是期望的改变。还希望将 openmode
作为其唯一参数的构造函数保持 explicit
。因此,需要增加构造函数声明的数量。 (另请参阅您链接到的页面上列出的缺陷报告。)
Is a single argument constructor with a default value the same as a default constructor?
不是真的,因为前者可以用参数调用。 :P 但是对于我相信你想要的问题,是的,所有参数都具有默认值的构造函数确实用作 class.
的默认构造函数Who's right? Is it necessary to manually call the base class constructor here?
崩溃往往意味着您有未定义的行为。至少,我不记得标准中要求将崩溃作为必需行为的任何部分。 :) 当行为未定义时,没有错误行为。 (大家都说得对。)