Я работал над этим весь день, поэтому я надеюсь, что не забуду каких-либо важных деталей, но здесь идет. Моя первоначальная цель состояла в том, чтобы создать фабрику игроков, которая заключала в себе логику создания игрока.
Вот как это выглядит:
Player PlayerFactory::CreatePlayer() {
Player constructee(id_generator++);
// c++1x move semantics says this isn't a copy!
return constructee;
}
Внутри проигрывателя есть составная переменная-член PlayerInputComponent. Этот объект PlayerInputComponent инкапсулирует логику работы с вводом игрока, для этого ему нужна ссылка / указатель на самого игрока. Достаточно просто, он принимает ссылку на игрока как единственный параметр своего конструктора.
Когда объект player создан, его список инициализаторов передает ссылку на себя в объект 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? Есть ли лучший способ решить эту проблему? Мне нравится семантическое значение наличия ссылки против указателя в этой ситуации, хотя я попробовал это с указателем и получил то же самое.
Может ли кто-нибудь объяснить мне, что происходит со ссылкой PlayerInputComponent на игрока, когда объект player перемещается из функции-члена CreatePlayer () и назначается «auto player»?
Для полноты здесь приведены объявления объекта:
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();
}