2012-10-13 47 views
2

如果我有一個STL列表,其中包含指向一個類的指針,並且想要訪問一個類成員,我該怎麼做?具體來說,我需要能夠刪除列表中的每個成員具有唯一標識的成員。STL鏈表::如何訪問成員?

所以我有這樣的:

class Actor{ 

    private: 
    int id; 

    public: 
    int getActorID(){ return id;}; 
}; 

std::list<Actor *> actorList; 

std::list<Actor *>::iterator i; 

所以,如果每個演員都有一個唯一的ID,我怎麼能去掉演員與特定的ID?我一直在使用手工編碼的鏈表,但我想將它切換到STL。唯一的問題是我無法弄清楚如何訪問方法getActorID()來查找要刪除的節點。謝謝你的幫助。

+4

您確定您想要的清單是?這聽起來更像是你在尋找地圖。 – oldrinb

+2

請重新考慮使用鏈接列表。如果你會遍歷這個列表,使用一個向量。如果你需要一個唯一的id與一個對象相關聯,使用一個map(或者C++ 11中的unordered_map)。鏈接列表對於大多數用途來說都很糟糕。 http://www.futurechips.org/thoughts-for-researchers/quick-post-linked-lists.html –

回答

1

迭代器的作用就像一個指針,以便在爲了調用需要解引用兩次存儲爲STL容器的指針的對象的成員函數:

std::list<Actor*>::iterator iter = actorList.begin(); 
(*iter)->getActorId(); 

或者:

(**iter).getActorId(); 
3
std::list<Actor *>::iterator it; 

std::list<Actor *>::iterator iStart = actorList.begin() ; 
std::list<Actor *>::iterator iEnd = actorList.end() ; 
for (it=iStart ;it!=iEnd;++it) 
{ 
if (*it->getActorId() == searchedId) 
    { 
    actorList.erase(it); 
    break; //you have unique id's so you could delete a maximum 1 item 
    } 
} 

也不要忘了,你有類似的替代品

std::list::remove 
std::list::remove_if 

http://en.cppreference.com/w/cpp/container/list/remove

+0

它的工作。感謝您的幫助(這對所有回答的人都有幫助!) – DayTripperID

+0

這有效嗎?除了其他問題之外,'delete'在該表達式中將不起作用。 –

+0

你是對的 - 我剛剛用擦除代替了刪除行。然而,我的意思是,它的工作原理是我能夠訪問節點成員。但是,實施並不奏效。許多海報指出,名單並不理想。我也嘗試過矢量,但也有問題。類Actor是一個基類,頂部有一個派生類,全部在創建時從堆中分配。是的,我必須非常頻繁地遍歷節點,所以我願意提供關於如何最好地實現它的想法。他們是遊戲的演員。 – DayTripperID

0

必須使用迭代器,因爲列表是一個連續的數據結構。 一旦你有一個迭代器,你可以向前移動,並使用間接運算符*

list<Actor *>::iterator it = actorList.begin(); 
Actor * innerPtr = *it; 
innerPtr->yourMethod(); 

一旦你知道,演員是要刪除的一個提取指向對象的指針,你可以使用的方法erase(position);使用迭代器:

if(innerPtr->getActorId() == <your condition>) 
{ 
    actorList.erase(it); 
} 

然而,如果需要使用演員ID來搜索,我建議您切換到一個不同的數據結構,例如一個關聯的容器(例如地圖)。

0

要找到你想要做的事的節點與您可以使用std::find_if()

#include <algorithm> 
#include <list> 
using namespace std; 


class Actor{ 

    private: 
    int id; 

    public: 
    int getActorID() const { return id;}; 
}; 


// a functor used for pre-C++11 since lambdas aren't supported 
struct isActor 
{ 
private: 
    int target; 

public: 
    isActor(int target) : target(target) {} 

    bool operator()(Actor const* pa) const 
    { 
     return pa->getActorID() == target; 
    } 
}; 


std::list<Actor *> actorList; 

std::list<Actor *>::iterator i; 

int main() 
{ 
    // pre-C++11 technique 
    i = std::find_if(actorList.begin(), actorList.end(), isActor(42)); 

    // C++11 lambda technique 
    int id = 42; 
    i = std::find_if(begin(actorList), end(actorList), [=](Actor const* pa) { 
     return pa->getActorID() == id; 
    }); 
} 
1

迭代器for循環在容器,可能使多個調用抹去的一個災難即將發生,因爲擦除通常在無效至少迭代器傳遞給它(以及任何指向擦除元素的其他迭代器),無效迭代器不能安全地遞增。只能進行一次擦除的循環可以使用「break」。在沒有任何使用無效迭代器的情況下退出for循環。

Iterator invalidation rules

正如我告訴我的同事造成這個問題多段錯誤的一個星期後,如果你要循環容器,並呼籲擦除,使用while循環,並確保你獲得在調用擦除之前,有效的迭代器到下一個項目(或end())。最簡單的方法是在呼叫站點後迭代迭代器。對於std :: list :: erase(iterator),也可以使用它的返回值作爲新的迭代器值。

list iterator not incrementable

+0

當前情況並不涉及在for循環中的多次擦除調用「列表中的成員,每個成員都有一個唯一的ID。」 –

+0

如果在單次調用擦除後不調用break,那麼當for循環頭被重新輸入並且迭代器增加時,代碼就變得不符合標準並且可能炸燬。 –

+0

迭代器是值,而不是引用。列表的迭代器的一個合法實現是使用內部數據結構的地址作爲迭代器值。那麼,在擦除之後,內部數據結構就被釋放了。通常,當您在運算符++中引用它時,死存儲器中仍然會有有效數據...但並非總是......如果不存在,則會出現災難性錯誤。 –