【问题标题】:C++ error: A reference of type cannot be initialized with a value of typeC++ 错误:无法使用类型值初始化类型引用
【发布时间】:2015-11-18 23:58:29
【问题描述】:

您好,我遇到了一个无法解决的问题。我正在创建一个带有智能指针的实体组件系统。

我得到的错误是:

std::unique_ptr<PrimaryComponent, std::default_delete<PrimaryComponent>> & 类型的引用(非 const 限定)不能用 std::unique_ptr<PlayerGraphics, std::default_delete<PlayerGraphics>> 类型的值初始化

游戏世界类:

auto GameWorld::Setup_World() -> void
{
    player->Attach_Component(player_Graphics);
    Add_GameObject(player);
}

游戏对象类附加组件功能:

void GameObject::Attach_Component(std::unique_ptr<PrimaryComponent> &component)
{
    if (component != nullptr)
    {
        component_container.push_back(component);
    }
}

player_Graphics和player的声明:

class GameWorld
{
private:
    std::vector<std::unique_ptr<GameObject>> gameObject_List;
    std::unique_ptr<GameObject> player;
    std::unique_ptr<PlayerGraphics> player_Graphics

playerGameObjectplayer_Graphics 是派生自 PrimaryComponent 的图形组件。

主要组件类:

class PrimaryComponent
{
protected:
public:
    PrimaryComponent();
    virtual ~PrimaryComponent();
    virtual void Render(GameObject &gameObject) = 0;
    virtual void Update(GameObject &gameObject, GameWorld &gameWorld, float gameTime) = 0;
};

PlayerGraphics 类:

class PlayerGraphics :
    public GraphicsComponent
{
public:
    PlayerGraphics();
    virtual ~PlayerGraphics();
    virtual void Render(GameObject &gameObject);
    virtual void Update(GameObject &gameObject, GameWorld &gameWorld, float gameTime);
};

PlayerGraphics 派生自 GraphicsComponent,而 GraphicsComponent 派生自 PrimaryComponent。

【问题讨论】:

  • player_Graphics 是如何声明的?它的确切类型是什么。你不显示它。
  • void GameWorld::Setup_World() 是所需的形式时,为什么要写auto GameWorld::Setup_World() -&gt; void?看起来更复杂的代码不会执行得更快。它也不会让你变得更聪明。
  • 不回答您的问题,但通过引用传递std::unique_ptr 有点矛盾。我的意思是,std::unique_ptr 是不可分享的,但通过使用引用,你是在分享它。
  • 您似乎用错误的类型调用 GameObject::Attach_Component。如果你打算使用智能指针,它们应该是相同的类型。
  • #Mateusz Grzejek - 不试图让代码更智能,只是玩弄 c++ 11/14 的功能,我知道它不会让代码更快或任何东西。

标签: c++ c++11


【解决方案1】:

问题出在参考文献中:

行:

void GameObject::Attach_Component(std::unique_ptr<PrimaryComponent> &component)

应该是:

void GameObject::Attach_Component(std::unique_ptr<PrimaryComponent> component)

然后,当你调用它时,而不是:

player->Attach_Component(player_Graphics);

你应该这样做:

player->Attach_Component(std::move(player_Graphics));

也就是说,函数应该拥有指针的所有权。请注意,原始的 player_Graphics 将设置为 null(您将其移入,如果您想保留对该对象的引用,那么您使用了错误的工具)。

您可能想知道为什么在您的代码中传递 std::unique_ptr&lt;PrimaryComponent&gt; 直接有效,而传递 std::unique_ptr&lt;PlayerGraphics&gt; 则无效。好吧,解释是您正在使用非常量引用,并且非常量引用只能绑定到完全相同时间的对象。但是,如果您按值传递参数,则智能指针将被移动,一切都会正常工作。

这一切都说得通,std::unique_ptr 是不可复制、不可共享、可移动的智能指针。您应该四处移动指针,而不是通过引用传递它。

TL;DR:如果BA 的子类,您可以将std::unique_ptr&lt;B&gt; 移动到std::unique_ptr&lt;A&gt;,但您不能将std::unique_ptr&lt;B&gt; 绑定到std::unique_ptr&lt;a&gt;&amp; 类型的引用。

PS。 move&cast的构造函数声明如下:

template <class T, class D = default_delete<T>>
class unique_ptr
{
    template <class U, class E>
    unique_ptr (unique_ptr<U,E>&& x) noexcept;
};

【讨论】:

  • 感谢您的回复。因此,当您创建对对象的引用很重要的实体/组件类时,原始指针是要走的路吗?
  • @Verdoner:这是一个需要在评论中回答的广泛问题!我的建议是决定对象的所有权(所有权或多或少是删除的责任)。如果所有权是唯一的,则 std::unique_ptr 很好(对同一对象的其他引用可能是原始指针)。如果所有权是共享的(最后一个删除指针删除对象),则使用std::shared_ptr。如果你决定了一个疯狂的方案,其中所有权根据一些标志而改变......好吧,然后是原始指针,手动删除,祝你好运;-)
  • 很好的答案...
【解决方案2】:

您似乎使用错误的类型调用 GameObject::Attach_Component。它需要std::unique_ptr&lt;PrimaryComponent&gt;,但您传递给它的是std::unique_ptr&lt;PlayerGraphics&gt;

编辑

PlayerGraphics 是否派生自 PrimaryComponent 无关紧要。这不适用于智能指针,只能使用原始指针。

【讨论】:

  • PlayerGraphics 是 PrimaryComponent 的派生类
  • 智能指针std::unique_ptrstd::shared_ptr,如果使用得当,都允许转换为基类的智能指针。正如我在回答中所说,问题不在于演员阵容,而在于引用,而且原始指针也会发生这种情况(想象Attach_Component(PrimaryComponent *&amp;component))。
猜你喜欢
  • 2020-06-12
  • 2023-03-15
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多