我是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();
}
}
答案 0 :(得分:3)
方法:
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
返回索引为0
的元素的可能是默认的副本(你的意思是忽略k
吗?)。如果您希望避免返回副本,则返回引用而不是索引0
的元素,而不是本地变量selectedUnit
:
Unit& UnitController::getUnit( int k )
{
return Units[k];
}
如果从k
删除了map
键入的条目,那么对该条目的Unit
具有引用的调用者现在具有悬空引用,则使用该引用是未定义的行为。有一些事情要考虑尝试避免这种情况:
UnitController
的客户是否需要直接访问Unit
中的map
?如果没有,客户端只需更新Unit
的某些属性,则修改UnitController
接口以支持Unit
的更新,而不提供客户端直接访问。std::shared_ptr<Unit>
而不是Unit
作为条目值类型(在这种情况下不通过引用返回) 。这将解决悬空引用问题,但调用者有权访问Unit
中不再存在的UnitController
是什么意思? operator[]
将在地图中为当前不存在的密钥创建一个条目:
使用key作为键和默认构造的映射值,将新元素插入容器,并返回对新构造的映射值的引用。如果具有键键的元素已存在,则不执行插入,并返回对其映射值的引用。
如果您不希望出现此行为,请使用find()
并确定如果密钥k
的条目不存在,应采取的操作。
答案 1 :(得分:2)
在此代码中:
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;
答案 2 :(得分:0)
您确实会收到一份深刻的单位副本。
考虑创建一个封装Unit的引用计数指针(也称为智能指针),并将其设置为map的值类型。
答案 3 :(得分:0)
当然你得到了副本。考虑一下:
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>>
?