Не требуется ли созданный по умолчанию конструктор для создания всех базовых классов?
Я сталкивался со случаем, когда безопасный с точки зрения типов 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;
}
1 ответ
У тебя есть B
создается неявно определенным конструктором копирования. Это, конечно, не зовет B::B()
, Если вы добавите следующий конструктор:
B(const B& other) : B()
{
*this = other;
}
вы увидите вывод:
B() -> INSERT: 0x7ffe57ef918f
B() -> INSERT: 0x7ffe57ef91b0
~B() -> ERASE: 0x7ffe57ef918f
~B() -> ERASE: 0x7ffe57ef91b0
Важно отметить следующее: каждый конструктор полностью создает объект. По умолчанию конструктор копирования не будет вызывать конструктор по умолчанию (и, очевидно, наоборот). Поэтому, если у вас есть что-то, что нужно сделать в каждом конструкторе, вы должны явно сделать это в каждом конструкторе, либо прямым вызовом, либо цепочкой конструктора.