2013-05-14 154 views
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(); 
    } 
} 

回答

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的條目現在有一個懸而未決的引用,其中使用的是未定義的行爲。有幾件事情要考慮,試圖避免這種情況:

  1. 是否的UnitController客戶需要在map直接訪問Unit?如果不是,並且客戶端只需要更新Unit的某些屬性,則修改UnitController接口以支持對Unit的更新,而不提供客戶端直接訪問。
  2. 如果客戶確實需要直接訪問,則可以考慮使用的std::shared_ptr<Unit>代替Unit入境值類型(和不要在這種情況下返回引用)。這將解決懸而未決的參考問題,但呼叫者有權訪問不在UnitController中的Unit是什麼意思?

operator[]將創建的地圖爲不關鍵的條目當前存在:

插入使用密鑰作爲密鑰和默認到容器上的新的元件構造映射值,並返回一個參考新構建的映射值。如果具有密鑰的元素已經存在,則不執行插入並返回其映射值的引用。

如果你希望沒有那麼此行爲使用find()並決定採取什麼行動,如果關鍵k的條目不存在服用。

+0

如果K> = Units.size()? :-) – user1764961 2013-05-14 10:53:06

+0

@ user1764961,它是一個'map',不是'vector'或'array'。 – hmjd 2013-05-14 10:54:54

+0

正好。我不認爲OP會對這種行爲感到滿意。 – user1764961 2013-05-14 10:58:33

0

您確實會收到Unit的深層副本。

考慮創建一個封裝Unit的引用計數指針(又名智能指針)並將其設置爲地圖的值類型。

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>>呢?

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; 
相關問題