从映射中检索对象实例
Retrieve object instance from map
我是C++新手,我想做一个小游戏。我有一个名为"UnitController"的类,它在映射中存储类"Unit"的多个实例。该类还有一个方法"getUnit",它应该返回一个存储的单元。
似乎这种方法只是部分有效。我想我得到了该单元的副本而不是请求的实例。
谁能指出我正确的方向?
#include "UnitController.h"
#include "Unit.h"
using namespace ci;
using std::map;
UnitController::UnitController()
{
}
void UnitController::addUnit( Vec2f position )
{
Unit mUnit = Unit();
mUnit.setup( position );
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
}
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
void UnitController::update()
{
for( map<int,Unit>::iterator u = Units.begin(); u != Units.end(); ++u ){
u->second.update();
}
}
void UnitController::draw()
{
for( map<int,Unit>::iterator u = Units.begin(); u != Units.end(); ++u ){
u->second.draw();
}
}
方法:
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
返回具有索引 0
的元素的副本(可能是默认的((您的意思是忽略k
吗?如果您希望避免返回副本,则返回对索引 0
处元素的引用,而不是对局部变量 selectedUnit
的引用:
Unit& UnitController::getUnit( int k )
{
return Units[k];
}
如果从map
中删除由 k
键控的条目,则引用该条目Unit
的调用方现在具有悬空引用,其使用是未定义的行为。要避免这种情况,需要考虑以下几点:
UnitController
客户端是否需要直接访问map
中的Unit
?如果不是,并且客户端只需要更新Unit
的某些属性,则修改UnitController
接口以支持对Unit
的更新,而无需提供客户端直接访问。- 如果客户端确实需要直接访问,请考虑对条目值类型使用
std::shared_ptr<Unit>
而不是Unit
(在这种情况下不要通过引用返回(。这将解决悬而未决的引用问题,但是调用方可以访问不再在UnitController
中的Unit
意味着什么?
operator[]
将在映射中为当前不存在的键创建一个条目:
使用 key 作为键和默认构造的映射值将新元素插入容器,并返回对新构造的映射值的引用。如果具有键键的元素已存在,则不执行插入,并返回对其映射值的引用。
如果您不希望出现此行为,请使用 find()
并决定在不存在键k
条目时要执行的操作。
在此代码中:
Unit UnitController::getUnit( int k ) { Unit selectedUnit = Units[0]; return selectedUnit; }
您按值返回Unit
,因此您实际上会获得原始Unit
的副本。
(另请注意,您似乎有一个错误,因为您使用0
作为键,而不是参数k
...
如果要修改原始Unit
(即存储在映射中的(,可以通过引用返回(Unit &
(:
Unit& UnitController::getUnit(int key)
{
return Units[k];
}
作为旁注,您可以简化插入代码。而不是使用std::map::insert()
方法:
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
你可以只使用std::map::operator[]
重载:
Units[ ...the key here... ] = mUnit;
您确实会收到一份 Unit 的深度副本。
考虑创建一个封装单位的引用计数指针(又名智能指针(,并将其设置为映射的值类型。
得到副本。 考虑一下:
void UnitController::addUnit( Vec2f position )
{
Unit mUnit = Unit(); // you create local instance of Unit
mUnit.setup( position );
// you add it to the map - actually the copy is created and stored in map
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
// mUnit is destroyed after the function exits
// your map would now contain a destroyed object if it wasn't a copy
}
除了您的getUnit
方法还返回一个副本。 这可能正常,也可能不正常,具体取决于客户端如何处理它。 如果它更改了返回的单元实例的状态,则它不会反映在映射中的副本中。
您可能想要使用map<int,Unit*>
但随后您需要照顾原始对象的生存期。您无法销毁它,因为指针将指向已销毁的对象。因此,正确的解决方案是使用shared_ptr<Unit>
但是,您的设计还有其他问题。将当前大小 + 1 存储为映射键,这意味着将其用作索引。为什么不直接使用std::vector<shared_ptr<Unit>>
呢?
- 对象实例化调用构造函数的次数太多
- 为什么C++无法识别我的对象实例化?
- 使用大括号和 : 符号的对象实例化
- 对象实例化与类型C++
- 如何在C++中传递lambda函数内部的对象实例
- 在 c++ 中重置大型对象实例的最佳方法是什么
- 从 QT Widget 对象实例访问 QT Widget 子成员
- C++阻止用户创建对象实例
- cpp 静态对象实例化
- C++:根据变量将同一对象实例化为多种类型之一
- 与 QML 共享C++对象实例
- C 对象实例被销毁后留在列表上
- vulkan vulkan.hpp从对象实例中获取opbject类型
- 用户创建的类对象实例化的未申请标识符
- 对象实例化后不输出
- 限制对象实例化堆
- C C#等价对象实例
- 在C 中运行时从指针访问对象实例
- 使用类/对象实例数据初始化对话框
- 未知的 C++ 对象实例化语法