1

我是 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();
    }
}
4

4 回答 4

3

方法:

Unit UnitController::getUnit( int k )
{
    Unit selectedUnit = Units[0];
    return selectedUnit;
}

正在返回带有索引的元素的可能默认副本0(您的意思是忽略k吗?)。如果您希望避免返回副本,则返回对 index 处元素的引用,而不是返回0局部变量selectedUnit

Unit& UnitController::getUnit( int k )
{
    return Units[k];
}

k如果从 中删除了键入的条目,map则具有对该条目的引用的调用者Unit现在具有一个悬空引用,其使用是未定义的行为。有几件事情需要考虑尝试避免这种情况:

  1. 的客户是否UnitController需要直接访问? 如果没有,客户端只需要更新 a 的某些属性,然后修改接口以支持更新,而不提供客户端直接访问。UnitmapUnitUnitControllerUnit
  2. 如果客户端确实需要直接访问,则考虑使用 astd::shared_ptr<Unit>而不是Unitfor 条目值类型(在这种情况下不要通过引用返回)。这将解决悬空引用问题,但是调用者可以访问Unit不再在 中的 a 意味着什么UnitController

operator[]将为当前不存在的键在映射中创建一个条目:

使用 key 作为键和默认构造的映射值将新元素插入容器,并返回对新构造的映射值的引用。如果具有键 key 的元素已经存在,则不执行插入并返回对其映射值的引用。

如果您不希望出现这种行为,请使用并决定如果 key 条目不存在find()时要采取的操作。k

于 2013-05-14T10:51:12.063 回答
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;
于 2013-05-14T10:54:56.883 回答
0

您确实会收到 Unit 的深层副本。

考虑创建一个引用计数指针(又名智能指针)封装一个 Unit 并将其设置为映射的值类型。

于 2013-05-14T10:52:01.400 回答
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>>呢?

于 2013-05-14T10:53:03.140 回答