GNU GCC (g++): почему он генерирует несколько dtor?
среда разработки: GNU GCC (g++) 4.1.2
пока я пытаюсь исследовать, как увеличить "покрытие кода - особенно покрытие функций" в модульном тестировании, я обнаружил, что некоторые из классов dtor, похоже, генерируются несколько раз. Кто-нибудь из вас знает почему, пожалуйста?
Я попытался и заметил, что я упомянул выше, используя следующий код.
В "тест.h"
class BaseClass
{
public:
~BaseClass();
void someMethod();
};
class DerivedClass : public BaseClass
{
public:
virtual ~DerivedClass();
virtual void someMethod();
};
In "испытание.ФКП"
#include <iostream>
#include "test.h"
BaseClass::~BaseClass()
{
std::cout << "BaseClass dtor invoked" << std::endl;
}
void BaseClass::someMethod()
{
std::cout << "Base class method" << std::endl;
}
DerivedClass::~DerivedClass()
{
std::cout << "DerivedClass dtor invoked" << std::endl;
}
void DerivedClass::someMethod()
{
std::cout << "Derived class method" << std::endl;
}
int main()
{
BaseClass* b_ptr = new BaseClass;
b_ptr->someMethod();
delete b_ptr;
}
когда я построил приведенный выше код (G++ test.cpp-o test), а затем посмотреть, какие символы были сгенерированы следующим образом,
nm -- demangle test
я мог видеть следующий вывод.
==== following is partial output ====
08048816 T DerivedClass::someMethod()
08048922 T DerivedClass::~DerivedClass()
080489aa T DerivedClass::~DerivedClass()
08048a32 T DerivedClass::~DerivedClass()
08048842 T BaseClass::someMethod()
0804886e T BaseClass::~BaseClass()
080488f6 T BaseClass::~BaseClass()
мои вопросы заключаются в следующем.
1) Почему было сгенерировано несколько dtors (BaseClass - 2, DerivedClass - 3)?
2) в чем разница между этими dtors? Как эти несколько dtors будут выборочно используется?
Теперь у меня есть ощущение, что для достижения 100% покрытия функций для проекта C++ нам нужно будет понять это, чтобы я мог вызвать все эти dtor в своих модульных тестах.
Я был бы очень признателен, если бы кто-то мог дать мне ответ на вышеизложенное.
2 ответа:
во-первых, цели этих функций описаны в Itanium C++ ABI; см. определения в разделах "базовый деструктор объектов", "полный деструктор объектов"и" удаление деструктора". Отображение на искаженные имена приведено в 5.1.4.
по сути:
- D2-это "деструктор базового объекта". Он уничтожает сам объект, а также элементы данных и невиртуальные базовые классы.
- D1 - это "полный деструктор объекта". Оно дополнительно уничтожает виртуальные базовые классы.
- D0-это "удаление объекта деструктора". Он делает все, что делает деструктор полного объекта, плюс он вызывает
operator deleteфактически освободить память.Если у вас нет виртуальных базовых классов, D2 и D1 идентичны; GCC будет, на достаточных уровнях оптимизации, фактически псевдонимы символов для одного и того же кода для обоих.
обычно существует два варианта конструктора (не отвечает/in-charge) и три деструктора (не отвечает/in-charge/в удаления).
The не отвечает ctor и dtor используются при обработке объекта класса, который наследуется от другого класса с помощью
virtualключевое слово, когда объект не является полным объектом (так что текущий объект не отвечает за построение или разрушение виртуального базового объекта). Этот ctor получает указатель на виртуальный базовый объект и сохраняет его.The in-charge ctor и dtors предназначены для всех остальных случаев, т. е. если нет виртуального наследования; если класс имеет виртуальный деструктор, то в удаления указатель dtor переходит в слот vtable, в то время как область, которая знает динамический тип объекта (т. е. для объектов с автоматическая или статическая продолжительность хранения) будет использовать in-charge dtor (потому что эта память не должна быть освобождена).
пример кода:
struct foo { foo(int); virtual ~foo(void); int bar; }; struct baz : virtual foo { baz(void); virtual ~baz(void); }; struct quux : baz { quux(void); virtual ~quux(void); }; foo::foo(int i) { bar = i; } foo::~foo(void) { return; } baz::baz(void) : foo(1) { return; } baz::~baz(void) { return; } quux::quux(void) : foo(2), baz() { return; } quux::~quux(void) { return; } baz b1; std::auto_ptr<foo> b2(new baz); quux q1; std::auto_ptr<foo> q2(new quux);результаты:
- запись dtor в каждом из vtables для
foo,bazиquuxукажите на соответствующий в удаления dtor.b1иb2построены вbaz()in-charge, которая называетfoo(1)in-chargeq1иq2построены вquux()in-charge, которая приходитсяfoo(2)in-charge иbaz()не отвечает с указателемfooобъект, который он построил ранееq2происходит от~auto_ptr()in-charge, который вызывает виртуальный dtor~quux()в удаления, которая называет~baz()не отвечает,~foo()in-charge иoperator delete.q1происходит от~quux()in-charge, которая называет~baz()не отвечает и~foo()in-chargeb2происходит от~auto_ptr()in-charge, который вызывает виртуальный dtor~baz()в удаления, которая называет~foo()in-charge иoperator deleteb1происходит от~baz()in-charge, которая называет~foo()in-chargeлюбой, кто происходит от
quuxбудет не отвечает ctor и dtor и взять на себя ответственность за создание