Нарушение прав доступа — почему деструктор базового класса вызывается дважды?

У меня есть класс Player который пытается реализовать Decorator шаблон. Playerсодержит член своего базового класса Character называется m_player, При вызове деструктора Player с клиента я сталкиваюсь с некоторыми проблемами, приводящими к нарушению доступа к памяти. Начиная в main:

Character* createBaseClass();

// more forward declarations

int main (int argc, char* const argv[])
{
Player* mainCharacter = new Player(createBaseCharacter());

delete mainCharacter;   // Crashes when calling delete

return 0;
}

Character* createBaseCharacter()
{
return Character::Builder()
.name("Dylan")
.description("Super bad-ass hero of the game")
.build();
}

Ошибка возникает вскоре после того, как я delete оператор на mainCharacter, который имеет следующую последовательность вызовов:

Player::~Player()
{
delete m_armor;
delete m_weapon;
delete m_player;  // calls Character's destructor
}

Тогда деструктор для Character:

Character::~Character()
{
// works fine
//
delete m_abilityAttributes;
m_abilityAttributes = NULL;
delete m_primaryAttributes;
m_primaryAttributes = NULL;
}

тем не мение, Странно то, что этот деструктор вызывается дважды — как только вышеперечисленное выполнено, выполнение отладчика приводит меня к разборке, проводя меня через «скалярный деструктор удаления», который, кажется, вызывает Character снова деструктор, через интерфейс для Player, называется CharacterDecorator:

введите описание изображения здесь

Стек вызовов в точке сбоя:

введите описание изображения здесь

Позвонить CharacterDecoratorдеструктор приводит к последующему вызову CharacterДеструктор:

Character::~Character()
{
// Crashes with Access Violation
//
delete m_abilityAttributes;
m_abilityAttributes = NULL;
delete m_primaryAttributes;
m_primaryAttributes = NULL;
}

На данный момент я полностью сбит с толку — я не уверен, почему деструктор снова вызывается через абстрактный интерфейс CharacterDecorator в дополнение к деструктору, вызываемому через его конкретную реализацию. Кроме того, добавление деструктора CharacterDecorator не кажется, чтобы решить проблему.

Для справки я включил реализацию Player, Character и интерфейс для CharacterDecorator:

class CharacterDecorator : public Character
{
public:

virtual Armor* getArmor() const = 0;
virtual Weapon* getWeapon() const = 0;
};

Player:

Player::Player()
{}

Player::Player(Character* player)
:m_player(player)
,m_weapon(0)
,m_armor(0)
{}

Player::Player(Character* player, Weapon* weapon, Armor* armor)
:m_player(player)
,m_weapon(weapon)
,m_armor(armor)
{}

Player::~Player()
{
delete m_armor;
delete m_weapon;
}

// getters
Armor* Player::getArmor() const
{
return m_armor;
}

Weapon* Player::getWeapon() const
{
return m_weapon;
}

// additional methods ...

Character:

Character::Character()
{}

Character::Character(const Builder& builder)
:m_name(builder._name)
,m_description(builder._description)
,m_abilityAttributes(builder._abilityAttributes)
,m_primaryAttributes(builder._primaryAttributes)
{}

Character::Character(const Character& rhs)
{
m_name = rhs.m_name;
m_description = rhs.m_description;
m_abilityAttributes = new AbilityAttributes();
m_primaryAttributes = new PrimaryAttributes();
*m_abilityAttributes = *rhs.m_abilityAttributes;
*m_primaryAttributes = *rhs.m_primaryAttributes;
}

Character::~Character()
{
delete m_abilityAttributes;
m_abilityAttributes = NULL;
delete m_primaryAttributes;
m_primaryAttributes = NULL;
}

// additional methods ...

// Builder pattern methods
//
Character::Builder::Builder()
: _abilityAttributes(0), _primaryAttributes(0)
{}

Character* Character::Builder::build()
{
return new Character(*this);
}

Character::Builder& Character::Builder::abilityAttributes(AbilityAttributes* value)
{
_abilityAttributes = value;
return *this;
}

Character::Builder& Character::Builder::primaryAttributes(PrimaryAttributes* value)
{
_primaryAttributes = value;
return *this;
}

1

Решение

Ваш Player класс наследует от CharacterDecorator, который наследует от Character, Поэтому, когда вы вызываете деструктор на Player объект, вы удалите объект m_player (вызывая его Character деструктор) потом опять на базу Character часть Player объект. Помимо того, что я делаю не то, что вы хотите сделать, у вас также есть проблема в том, что когда вы создали Player, по умолчанию Character конструктор был вызван для создания базы Character объект, и этот ничего не инициализирует в Character часть Player то есть такие поля, как m_abilityAttributes а также m_primaryAttributes что вы удаляете в Character деструктор.

Теперь, кажется, у вас тоже может Character в вашем Player, Вы, вероятно, хотите иметь свой Player конструктор, принимающий Character::Builder ссылка вместо Character указатель, который будет использоваться для инициализации / построения базы Character вашего персонажа(and you may have to have aCharacterDecoratorconstructor taking aХарактер :: Builderobject to initialize itsБаза персонажей).

(примечание: наличие члена m_player, указывающего на Character был красный флаг для меня)

2

Другие решения

Хотя я предоставил конструктор, который не принимает аргументов, я не дал ему список инициализации для членов типа указателя:

Character::Character()
{}

Должно быть:

Character::Character()
: m_abilityAttributes(0), m_primaryAttributes(0)
{}

Я думаю, это потому, что конструктор для базового класса Character вызывается, когда я создаю экземпляр объекта Player, но конструктор по умолчанию для базового класса ранее не имел списка инициализации членов, поэтому возникла ошибка нарушения доступа при вызове базового деструктора (?)

0

По вопросам рекламы [email protected]