c++ - 访问冲突 - 为什么基类析构函数被调用两次?

标签 c++ inheritance decorator access-violation virtual-destructor

<分区>

我有一个 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();
}

错误发生在我调用 mainCharacter 上的 delete 运算符后不久,它具有以下调用顺序:

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;
}

但是,奇怪的是这个析构函数似乎被调用了两次 - 一旦完成上述操作,执行调试器就会带我进行反汇编,逐步执行“标量删除析构函数”,它似乎通过 Player 的接口(interface)再次调用 Character 析构函数,称为 CharacterDecorator:

enter image description here

崩溃时的调用堆栈:

enter image description here

调用 CharacterDecorator 的析构函数会导致随后调用 Character 的析构函数:

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

在这一点上,我完全感到困惑 - 除了通过其具体实现调用析构函数之外,我不确定为什么通过抽象接口(interface) CharacterDecorator 再次调用析构函数。此外,向 CharacterDecorator 添加析构函数似乎无法解决问题。

作为引用,我包含了PlayerCharacter 的实现和CharacterDecorator 的接口(interface):

class CharacterDecorator : public Character
{
public:

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

播放器:

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(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 对象,这个对象不会初始化 PlayerCharacter 部分中的任何内容,即像 m_abilityAttributes 这样的字段> 和您在 Character 析构函数中删除的 m_primaryAttributes

现在,您的 Player 中似乎也有一个 Character。您可能希望让您的 Player 构造函数采用 Character::Builder 引用而不是 Character 指针,后者将用于初始化/构建你的 'CharacterDecorator 的基本 Character(你可能必须有一个 CharacterDecorator 构造函数接受一个 Character::Builder 对象来初始化它的字符`基数)。

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

关于c++ - 访问冲突 - 为什么基类析构函数被调用两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14146572/

相关文章:

c++ - 使用LD链接中间文件

c++ - 我正在编写一个非常简单的字母评分系统,if 语句是否最有效?

c++ - 尝试一次取 1 个随机数字

C++ 抽象函数对象在与 std::accumulate 一起使用时会导致混淆行为

python - 缓存装饰器 Python

c++ - 在运行时从表单中删除 TFrame

java - 如何将java类(从一个包)继承到另一个类(在另一个包中)

java - 将方法委托(delegate)给Java中的子类

c++ - 装饰者模式中的装饰顺序

python - functools.partial 以及它如何组成非关键字参数