0

内部Builderオブジェクトを使用して複雑なオブジェクトをインスタンス化するコンストラクターがあります。データ構造のメンバーのうち 5 つはポインター型です。ただし、このパターンを使用すると、オブジェクトが破棄されるときに問題が発生します。以下は、メンバーの初期化リストを使用して、コンストラクターがどのように見えるかです。

Player::Player(const Builder& builder) 
    :m_name(builder._name)
    ,m_description(builder._description)
    ,m_primaryAttributes(builder._primaryAttributes)
    ,m_abilityAttributes(builder._abilityAttributes)
    ,m_armor(builder._armor)
    ,m_weapon(builder._weapon)
    ,m_inventory(new ComponentMap())
{}

期待どおり、クライアント コードは正常に動作します。

Player* player = Player::Builder()
    .name("Dylan")
    .description("Super bad-ass hero of the game")
    .primaryAttributes(createPrimaryAttributes())
    .abilityAttributes(createAbilityAttributes())
    .weapon(createWeapon())
    .armor(createArmor())
    .build();

ただし、メッセージ チェーンで引数の 1 つを省略してからPlayerオブジェクトを破棄すると、悪いことが起こります。

Player* player = Player::Builder()
    .name("Dylan")
    .description("Super bad-ass hero of the game")
    .primaryAttributes(createPrimaryAttributes())
    .abilityAttributes(createAbilityAttributes())
    .armor(createArmor())
    .build();

// ...

delete player;

// ...

// cleanMemory() gets called in Player::~Player()
void Player::cleanMemory()
{
    if(m_primaryAttributes != NULL )
        delete m_primaryAttributes;
    if(m_abilityAttributes != NULL )
        delete m_abilityAttributes;
    if(m_inventory != NULL )
        delete m_inventory;
    if(m_weapon != NULL)          // oops, bad stuff happens here
        delete m_weapon;
    if(m_armor != NULL)
        delete m_armor;
}

NULL明らかに、これは、武器のポインタがどちらかまたはオブジェクトのインスタンスに初期化されなかったために発生しWeaponます。コンストラクターは、チェーンから1つのメソッドが省略された場合に、 NULL(少なくとも私が見ることができるものから)デフォルトを許可していないようです。Builder現時点では、クライアントはオブジェクトWeaponへのポインタNULLまたはインスタンスのいずれかを指定する必要があります。

Builderこのコンストラクタを完全に修正せずにこれを回避する方法はありますか? または、これを などの別のパターンを使用してリファクタリングしFactory、位置パラメーター リストを使用して通常のコンストラクターに戻す必要がありますか?

4

1 に答える 1

1

あなたが参照したサンプルコードはあまり良いコードベースではありません。以下に提案しますbuild pattern

class Builder
{
   Weapon* BuildWeapon() { return new Weapon(); }
   Armor*  BuildArmor(); { return new Armor(); }    
};

class Player
{
public:
  Player(const Builder& builder) 
  : weapon_ptr(builder.BuildWeapon()),
    armer_ptr(builder.BuildArmor())

private:
  std::shared_ptr<Weapon> weapon_ptr;
  std::shared_ptr<Armor>  armor_ptr;
};   

利用方法:

Builder builder;
std::shared_ptr<Player> player(new Player(builder));

または、単に

class Player2
{
public:
  Player() {}
  void SetWeapon(Weapon* p) { weapon_ptr.reset(p); }
  void SetArmor(Armor* p) { armor_ptr.reset(p); }

private:
  std::shared_ptr<Weapon> weapon_ptr;
  std::shared_ptr<Armer>  armer_ptr;
};

利用方法:

   Builder builder;
   std::shared_ptr<Player> player;
   player->SetWeapon(builder.BuildWeaper());
   player->SetArmor(builder.BuildArmor());

deleteWeapon_ptr、armer_ptr はスマート ポインターであるため、動的に割り当てられたメモリを呼び出す必要がなくなり、cleanMemory()関数を削除できます。

これは単純なサンプルです。プレーヤーのインターフェイスを拡張して、プレーヤー オブジェクトの作成後に別の要素を構築する機能を提供できます。

于 2013-01-03T06:08:10.897 に答える