У меня есть класс 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;
}
Ваш 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 a
CharacterDecoratorconstructor taking a
Характер :: Builderobject to initialize its
База персонажей).
(примечание: наличие члена m_player, указывающего на Character
был красный флаг для меня)
Хотя я предоставил конструктор, который не принимает аргументов, я не дал ему список инициализации для членов типа указателя:
Character::Character()
{}
Должно быть:
Character::Character()
: m_abilityAttributes(0), m_primaryAttributes(0)
{}
Я думаю, это потому, что конструктор для базового класса Character
вызывается, когда я создаю экземпляр объекта Player
, но конструктор по умолчанию для базового класса ранее не имел списка инициализации членов, поэтому возникла ошибка нарушения доступа при вызове базового деструктора (?)