1

私はこれで一日中働いているので、重要な詳細を忘れないことを願っていますが、ここに行きます。私の当初の目標は、プレーヤーの作成方法のロジックをカプセル化したプレーヤーファクトリを作成することでした。

これは次のようになります。

Player PlayerFactory::CreatePlayer() {

    Player constructee(id_generator++);

    // c++1x move semantics says this isn't a copy!
    return constructee;
}

プレーヤー内には、複合PlayerInputComponentメンバー変数があります。このPlayerInputComponentオブジェクトは、プレーヤー入力を処理するロジックをカプセル化します。これを行うには、実際のプレーヤー自体への参照/ポインターが必要です。非常に簡単ですが、コンストラクターへの唯一のパラメーターであるため、プレーヤーへの参照を取ります。

プレーヤーオブジェクトが作成されると、その初期化子リストはそれ自体への参照をPlayerInputComponentオブジェクトに渡します。外観は次のとおりです。

Player::Player(const unsigned int id) 
    : id(id), 
    input_component(*this)
{
...
}

イニシャライザリスト内でこれを参照解除することは通常は悪い考えであることを理解していますが、PlayerInputComponentオブジェクト内で参照を設定するために使用しているだけです。コンストラクターは次のとおりです。

PlayerInputComponent::PlayerInputComponent(Player &player) 
    : player_entity(player) { // set the reference, it is never used within the constructor body
}

何らかの理由で、プレーヤーファクトリが作成したプレーヤーのローカルコピーを返すと、参照が文字化けします。私の意図は、スタック上に作成されたプレーヤーのインスタンスを移動して、呼び出し先に割り当てることでした。これは次のようになります。

auto player = player_factory.CreatePlayer();

コードが実行された後、プレーヤーの複合PlayerInputComponentオブジェクトのそのプレーヤーへの参照がマングルされます。ファクトリがローカルプレーヤーオブジェクトを呼び出し先に返すときにプレーヤーの移動コンストラクターが呼び出されることを理解していますが、PlayerInputComponent内のプレーヤーの参照はどうなりますか?この問題を解決するためのより良い方法はありますか?私はこの状況で参照とポインターを持つという意味的な意味が好きですが、ポインターを使って試して同じことをしました。

プレーヤーオブジェクトがCreatePlayer()メンバー関数から移動され、「自動プレーヤー」に割り当てられたときに、PlayerInputComponentのプレーヤーへの参照に何が起こっているのかを誰かが私に説明できますか?

完全を期すために、オブジェクトの宣言を次に示します。

class PlayerInputComponent {

private:
    Player &player_entity;
    void HandleKeyboardInput();
public:
    //PlayerInputComponent(PlayerInputComponent &&other);
    //PlayerInputComponent(const PlayerInputComponent &other);
    PlayerInputComponent(Player &player);
    void Update();
};

そしてここにプレーヤーがあります:

class Player : public Entity{
    friend class PlayerFactory;
private:
    const unsigned int id;

public:
    Player(const unsigned int id);

    // components
    PlayerInputComponent input_component;
};

問題をコンパイル/デモンストレーションする正確な動作を示す小さな例を以下に再構築しました。ありがとうございました!

class B;

class A  {
public:
    A(B& bb) : b(bb) { }

private:
    B &b;
};

class B {
public:
    B() : a(*this) { othercrap = othercrap2 = 0; }
    int othercrap;
    int othercrap2;
private:
    A a;
};

class BFactory {
public:
    B CreateB() {
    B temp;
        return temp;
    };
};

B start() {
    BFactory fac;
    auto bi = fac.CreateB();

    return bi;
}

int main(int argc, char *argv[]) {
    auto i = start();
}
4

2 に答える 2

5

移動すると参照が無効になります。(オブジェクトではなく、保管場所が参照されます)

移動すると新しいオブジェクトが作成されることに注意してください(そのため、名前はmoveコンストラクターです)。コンテンツの所有権は譲渡されますが、オブジェクトは実際にはメモリ内の新しい場所に移動されません。新しいオブジェクトが作成された後、破棄されます。

Player新しいオブジェクトで参照を適切にバインドするには、のコピーおよび移動コンストラクターを定義する必要があります。

于 2012-02-20T03:39:22.733 に答える
1

サンプルで移動セマンティクスを確認できません。CreateBは、その内部一時変数(temp)を取得します。これは、 biに割り当てられるreturnの一時オブジェクト(xvalue)に簡単にコピーされます。参照は、すでに破棄されているローカルの一時オブジェクトへの参照を簡単にコピーするため、文字化けします。

于 2012-02-20T03:40:41.987 に答える