【发布时间】:2020-02-10 12:22:23
【问题描述】:
我正在关注有关创建实体组件框架的教程。它使用组合(一个实体有一组组件)。
class Component
{
public:
Entity* entity;
//VIRTUAL VOID INITIALIZE, DRAW, UPDATE functions here
private:
std::unique_ptr<Entity> m_pEntity;
};
class Entity
{
public:
//Add component function
template <typename T, typename... TArgs>
T& addComponent(TArgs&&... mArgs)
{
T* LComponent(new T(std::forward<TArgs>(mArgs)));
LComponent->entity = this;
std::unique_ptr<Component> uPtr{ LComponent };
m_pComponents.emplace_back(std::move(uPtr));
m_ComponentArray[getComponentTypeID<T>()] = LComponent;
LComponent->ECS_init();
return *LComponent;
}
private:
bool m_IsActive = true;
std::vector <std::unique_ptr<Component>> m_pComponents;
std::array<Component*, gMaxComponents> m_ComponentArray;
};
但是,作者没有很好地解释背后的逻辑,我无法理解 addComponent 函数的语法。特别是:
- 为什么在将
uPtr添加到向量时需要将uPtr转换为右值引用m_pComponents.emplace_back(std::move(uPtr))
【问题讨论】:
-
考虑到
addComponent根本没有返回任何东西,第一点变得没有意义。否则(如果您添加显式return语句)按值或按引用返回对象之间的区别与按值或按引用获取参数的函数非常相关。因此,如果您知道这种差异,您也应该了解返回类型的差异。 -
您在一个问题中同时提出许多问题。通常,多个问题应作为多个单独的 Stackoverflow 问题提出。每个问题一个问题。
-
至于
new T...好吧,如果你改用new Component,那对你来说更有意义吗?new T为T类型的对象分配内存,然后构造该对象。T的类型无关紧要,它对 anyT的行为相同(不管是Component、std::vector<Component>还是int)。 -
在“emplace_back(std::move(uPtr))”的情况下,它只是一个唯一指针的想法,即只有一个“拥有”某物的唯一实例。因此,为了插入向量,所有权必须“移动”到向量中。因此, std::move 用于实现这一目标。因此 std::move 在技术上是对 && 的强制转换,但在移动所有权时也使其可读。常见的误解是,人们感觉“对象”被移动了,但事实并非如此。这只是关于传递所有权。
-
std::move 既没有传输也没有移动,它只转换为 &&。采用右值 ref (&&) 的函数应该实现“请取得所有权!”的语义。在你的情况下,你有:
std::vector <std::unique_ptr<Component>> m_pComponents;所以向量内的指针对Component对象具有唯一的所有权。因此,您使用new在堆上创建一个新对象,并将m_pComponents.emplace_back(std::move(uPtr));的所有权传递给向量。emplace_back( T&& )将真正接管所有权是约定俗成的,语言本身并不能保证。
标签: c++ templates rvalue-reference type-deduction