1

我有一个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在我调用操作员 on后不久发生错误,该操作员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似乎并不能解决问题。

作为参考,我已经包含了 的实现PlayerCharacter接口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;
}
4

2 回答 2

2

您的Player类继承自CharacterDecorator,继承自Character。因此,当您在Player对象上调用析构函数时,您将删除 m_player 对象(调用其Character析构函数),然后再次在对象的基础Character部分上Player。除了我不是你想要做的事情之外,你还有一个问题,当你创建时Player,默认Character构造函数被调用来创建基础Character对象,而这个没有初始化任何Character部分即像和你在析构函数中删除的Player字段。m_abilityAttributesm_primaryAttributesCharacter

现在,Character您的Player. 您可能希望您的Player构造函数采用Character::Builder引用而不是Character指针,该指针将用于初始化/构建Character您的“CharacterDecorator (and you may have to have aCharacterDecorator constructor taking aCharacter::Builder object to initialize itsCharacter”基础的基础)。

(注意:有一个 m_player 成员指向 aCharacter对我来说是一个危险信号)

于 2013-01-04T01:43:52.837 回答
0

虽然我提供了一个不带参数的构造函数,但我没有给它一个指针类型成员的初始化列表:

Character::Character() 
{}

应该:

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

我猜这是因为基类的构造函数Character在我实例化 的对象时被调用Player,但是基类的默认构造函数之前没有成员初始化列表,因此调用基析构函数时出现访问冲突错误 (? )

于 2013-01-04T01:27:57.863 回答