是否不需要默认生成的构造函数来构造所有基数 类?
Is a default-generated constructor not required to construct all base classes?
我遇到过类型安全的 c++ 产生不匹配的情况 ctor/dtors。
下面的代码为A生成了两个构造函数,默认构造函数也构造了它的base(B),但是默认生成的copy/move ctor不构造B,后来又销毁了B,所以我们得到了不匹配的ctor/dtor。
我已经用 gcc 和 clang 试过了,但都失败了。在 gcc 错误报告论坛中,他们建议这不是 gcc 问题。
我可能遗漏了一些东西,但是当类型安全代码导致 dtor 调用尚未构造的 class 时,难道没有什么奇怪的吗?
程序输出:
B() -> INSERT: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b40 // <- unmatched dtor call
Assertion failed: (!all.empty()), function ~B, file gcc_bug.c, line 20.
代码如下:
#include <set>
#include <iostream>
#include <cstdint>
#include <cassert>
#include <experimental/optional>
std::set<std::uintptr_t> all;
struct B
{
B()
{
std::cerr << "B() -> INSERT: " << this << "\n";
all.insert((std::uintptr_t)this);
}
~B()
{
std::cerr << "~B() -> ERASE: " << this << "\n";
assert(!all.empty()); // FAILS
assert(all.find((std::uintptr_t)this) != all.end()); // FAILS
all.erase((std::uintptr_t)this);
}
};
struct A : B {};
static std::experimental::optional<A> f()
{
A a;
return a;
}
int main()
{
auto a = f();
return 0;
}
您有一个 B
是由隐式定义的复制构造函数创建的。当然,这不是调用 B::B()
。如果添加以下构造函数:
B(const B& other) : B()
{
*this = other;
}
您将看到输出:
B() -> INSERT: 0x7ffe57ef918f
B() -> INSERT: 0x7ffe57ef91b0
~B() -> ERASE: 0x7ffe57ef918f
~B() -> ERASE: 0x7ffe57ef91b0
需要注意的重要一点是:每个 构造函数都完整地构造了对象。默认情况下,复制构造函数不会调用默认构造函数(显然,反之亦然)。因此,如果您需要在每个构造函数中完成某些操作,则必须通过直接调用或通过构造函数链接在每个构造函数中明确地执行此操作。
我遇到过类型安全的 c++ 产生不匹配的情况 ctor/dtors。 下面的代码为A生成了两个构造函数,默认构造函数也构造了它的base(B),但是默认生成的copy/move ctor不构造B,后来又销毁了B,所以我们得到了不匹配的ctor/dtor。
我已经用 gcc 和 clang 试过了,但都失败了。在 gcc 错误报告论坛中,他们建议这不是 gcc 问题。 我可能遗漏了一些东西,但是当类型安全代码导致 dtor 调用尚未构造的 class 时,难道没有什么奇怪的吗?
程序输出:
B() -> INSERT: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b40 // <- unmatched dtor call
Assertion failed: (!all.empty()), function ~B, file gcc_bug.c, line 20.
代码如下:
#include <set>
#include <iostream>
#include <cstdint>
#include <cassert>
#include <experimental/optional>
std::set<std::uintptr_t> all;
struct B
{
B()
{
std::cerr << "B() -> INSERT: " << this << "\n";
all.insert((std::uintptr_t)this);
}
~B()
{
std::cerr << "~B() -> ERASE: " << this << "\n";
assert(!all.empty()); // FAILS
assert(all.find((std::uintptr_t)this) != all.end()); // FAILS
all.erase((std::uintptr_t)this);
}
};
struct A : B {};
static std::experimental::optional<A> f()
{
A a;
return a;
}
int main()
{
auto a = f();
return 0;
}
您有一个 B
是由隐式定义的复制构造函数创建的。当然,这不是调用 B::B()
。如果添加以下构造函数:
B(const B& other) : B()
{
*this = other;
}
您将看到输出:
B() -> INSERT: 0x7ffe57ef918f
B() -> INSERT: 0x7ffe57ef91b0
~B() -> ERASE: 0x7ffe57ef918f
~B() -> ERASE: 0x7ffe57ef91b0
需要注意的重要一点是:每个 构造函数都完整地构造了对象。默认情况下,复制构造函数不会调用默认构造函数(显然,反之亦然)。因此,如果您需要在每个构造函数中完成某些操作,则必须通过直接调用或通过构造函数链接在每个构造函数中明确地执行此操作。