我整天都在工作,所以我希望我不要忘记任何重要的细节,但是这里有。我最初的目标是建立一个播放器工厂,其中封装了如何创建播放器的逻辑。

看起来像这样:

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对象对其播放器的引用将被破坏。我知道,当工厂将本地播放器对象返回给被调用者时,将调用播放器的move构造函数,但是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();
}

最佳答案

移动会使引用无效。 (引用的是存储位置,而不是对象)

请记住,移动会创建一个新对象(因此,请移动构造函数)。内容的所有权已转移,但对象实际上并未移动到内存中的新位置。构造新对象后将其销毁。

您应该定义Player的copy和move构造函数,以将引用正确绑定(bind)到新对象中。

10-08 08:19
查看更多