我整天都在工作,所以我希望我不要忘记任何重要的细节,但是这里有。我最初的目标是建立一个播放器工厂,其中封装了如何创建播放器的逻辑。
看起来像这样:
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)到新对象中。