1

我遇到过类型安全的 c++ 产生不匹配的 ctor/dtors 的情况。以下代码为 A 生成了两个构造函数。默认构造函数也构造了它的基 (B),但默认生成的复制/移动 ctor 不构造 B。后来,它破坏了 B,所以我们得到不匹配的 ctor/dtor。

我已经用 gcc 和 clang 尝试过,但都失败了。在 gcc 错误报告论坛中,他们建议这不是 gcc 问题。我可能遗漏了一些东西,但是当类型安全代码导致对尚未构造的类的 dtor 调用时,难道没有什么奇怪的吗?

程序输出:

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;
}
4

1 回答 1

3

您有一个B由隐式定义的复制构造函数创建的。当然,这不是调用B::B(). 如果添加以下构造函数:

B(const B& other) : B()
{
    *this = other;
}

你会看到输出:

B() -> INSERT: 0x7ffe57ef918f
B() -> INSERT: 0x7ffe57ef91b0
~B() -> ERASE: 0x7ffe57ef918f
~B() -> ERASE: 0x7ffe57ef91b0

要带走的重要一点是:每个构造函数都完全构造了对象。默认情况下,复制构造函数不会调用默认构造函数(显然,反之亦然)。因此,如果您需要在每个构造函数中执行某些操作,则必须在每个构造函数中显式地执行此操作,或者通过直接调用,或者通过构造函数链接。

于 2016-07-07T23:29:31.460 回答