移动所有者时,对所有者的C++复合引用已损坏

Sho*_*ort 1 c++ reference move-constructor

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

这是看起来像:

Player PlayerFactory::CreatePlayer() {

    Player constructee(id_generator++);

    // c++1x move semantics says this isn't a copy!
    return constructee;
}
Run Code Online (Sandbox Code Playgroud)

在播放器中,有一个复合的PlayerInputComponent成员变量.这个PlayerInputComponent对象封装了处理玩家输入的逻辑,为此,它需要一个指向实际玩家本身的引用/指针.很容易,它引用了播放器,因为它是它的构造函数的唯一参数.

构造播放器对象时,它的初始化列表将对自身的引用传递给PlayerInputComponent对象.以下是它的外观:

Player::Player(const unsigned int id) 
    : id(id), 
    input_component(*this)
{
...
}
Run Code Online (Sandbox Code Playgroud)

我知道在初始化列表中取消引用它通常是一个坏主意,但我只是用它在PlayerInputComponent对象中设置引用.这是构造函数:

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

无论出于何种原因,当玩家工厂返回其创建的玩家的本地副本时,引用会出现乱码.我的意图是,在堆栈上创建的玩家的实例被移动并分配给被调用者.这看起来如下:

auto player = player_factory.CreatePlayer();
Run Code Online (Sandbox Code Playgroud)

代码执行后,播放器的复合PlayerInputComponent对象对它的引用被破坏了.我知道当工厂将本地播放器对象返回给被调用者时,会调用播放器的移动构造函数,但是PlayerInputComponent中播放器的引用会发生什么?有没有更好的方法来解决这个问题?我喜欢在这种情况下使用引用vs指针的语义,虽然我确实用指针尝试它并得到相同的东西.

任何人都可以向我解释当玩家对象移出CreatePlayer()成员函数并分配给"自动播放器"时,PlayerInputComponent对玩家的引用会发生什么?

为了完整性,这里是对象的声明:

class PlayerInputComponent {

private:
    Player &player_entity;
    void HandleKeyboardInput();
public:
    //PlayerInputComponent(PlayerInputComponent &&other);
    //PlayerInputComponent(const PlayerInputComponent &other);
    PlayerInputComponent(Player &player);
    void Update();
};
Run Code Online (Sandbox Code Playgroud)

这是玩家:

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

public:
    Player(const unsigned int id);

    // components
    PlayerInputComponent input_component;
};
Run Code Online (Sandbox Code Playgroud)

我重新构建了一个下面的小例子,它显示了确切的行为,它编译/演示了这个问题.谢谢!

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();
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 5

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

请记住,移动创建一个新对象(因此名称,移动构造函数).传输内容的所有权,但实际上对象不会移动到内存中的新位置.它在构造新对象后被销毁.

您应该定义Player复制并移动构造函数以正确绑定新对象中的引用.