簡體   English   中英

如何將列表STL的迭代器轉換為實例(C ++)

[英]how to convert iterator of list STL to instance (C++)

這是我第一次使用STL列表,我不確定我是否有可能做到這一點。 我有class_B,它包含class_A的列表,我需要一個帶有ID的class_B中的函數,在列表中搜索具有相同ID的實例,並從列表中獲取指向該列表中實例的指針:

bool class_B::get_pointer(int ID,class_A* pointer2A){

   list<class_A>::iterator i;
   for(i=class_A.begin();i!=class_A.end();i++){
       if((*i).get_id()==ID) {
           \\pointer2A=(i);<---------------this is what I'm trying to do
           return true;
       }
   }
   pointer2A=NULL;
   return false;
}

我該如何執行此操作,是否可以從迭代器轉換為實例?

編輯:

我在多線程程序中使用此函數,我無法將迭代器返回到調用函數,因為另一個線程可能會刪除列表中的元素。

現在我有一個指向我的元素的指針(並且假設它被鎖定以便它不能被刪除),並且另一個線程移除了另一個元素並在列表上執行排序,我將持有的指針會發生什么? (我不知道列表如何重新排列元素,是通過使用復制c'tor復制元素還是通過其他方法來完成?)。

在我的情況下, 無用的答案是最有幫助的(非常感謝),是的,我應該使用對指針的引用,因為我正計划改變它。

你應該這樣寫:

pointer2A= &*i;

這里*i返回的對象,你可以通過前綴&作為地址獲得: &*i

請注意, i&*i 有關更一般的討論,請參閱此主題:


無論如何,我建議你把指針本身讀作:

class_A* class_B::get_pointer(int ID)
{
   //I assume the name of the list is objA, not class_A
   for(list<class_A>::iterator i=objA.begin();i!=objA.end();i++)
   {
       if( i->get_id()==ID) 
       {
           return &*i;
       }
   }
   return NULL; //or nullptr in C++11 
}

或者,在C ++ 11中,您可以使用std::find_if作為:

auto it = std::find_if(objA.begin(), 
                       objA.end(), 
                       [&](class_A const &a){ return a->get_id() == ID;});
classA *ptr = NULL;
if ( it != objA.end())
     ptr = &*it; //get the pointer from iterator

確保get_idconst成員函數。

if(i->get_id()==ID) {
    pointer2A=&*i;
    return true;
}

迭代器被設計為具有與指針類似的語義,因此例如,您可以編寫i->get_id()就像您有一個指向A的指針一樣。

類似地, *i產生一個引用A& ,並且&*i將其轉換回指針 - 它看起來有點笨重(如果i真的是一個指針,它將是一個身份操作),但它是慣用的。

請注意,這不會做你想要的任何事情 - 調用者的class_A* pointer2A按值傳遞 ,所以只有get_pointer的指針副本被修改,調用者才會看到該值。 嘗試這個:

bool class_B::get_pointer(int ID, class_A *& pointer2A)
{
    list<class_A>::iterator i;
    for(i=class_A.begin();i!=class_A.end();i++) {
        if(i->get_id()==ID) {
            pointer2A=&*i;
            return true;
        }
    }
    pointer2A=NULL;
    return false;
}   

現在, pointer2A通過引用傳遞,因此調用者的副本會在函數內被修改。

順便說一下,你可以從右到左讀取參數聲明class_A * & pointer2A ,因為“pointer2A是對class_A指針的引用”。

如果你有一個iterator ,你可以通過簡單地解除引用迭代器(它給你一個引用),然后獲取它的地址(它給你一個指針)來獲得一個原始指針。 所以,在你的情況下:

pointer2A = &*i;

這可能看起來像一個奇怪的,笨拙的方式獲得一個指針,它是。 但是當您使用Std Lib中的集合和迭代器時,通常不關心指針。 迭代器是將“STL”組合在一起的粘合劑。 這就是你應該處理的問題,而不是原始指針。

你上面寫的循環肯定會完成你想要完成的工作,但是有更好的方法來實現相同的目標。 (更好是一個主觀術語。)特別是, <algorithm>庫提供std::findstd::find_if ,它們就像他們所說的一樣。 他們在集合中找到了一些東西。 find會找到與你正在尋找的東西相等的東西。 find_if將找到與您指定的某些條件匹配的內容。 后者是這里使用的合適算法,有兩種主要方法可以使用它。

第一種更“傳統”的方法是使用仿函數:

struct match_id : public std::unary_function<bool, class_A>
{
  match_id(int ID) : id_(id) {};
  bool operator()(const class_A* rhs) const
  {
    if( id_ == rhs->get_id() )
      return true;
    else
      return true;
};

/* ... */

list<class_A>::iterator it = std::find_if(objA.begin(), objA.end(), match_id(ID));

此方法適用於C ++ 03或C ++ 11。 有些人不喜歡它,因為它相當冗長。 另一方面,我喜歡它,因為實際的商務邏輯( find_if調用)比顯式循環更簡潔,更具表現力。

在C ++ 11中,您可以使用lambda代替仿函數:

unsigned ID = 42;
std::find_if( objA.begin(), objB.end(), [&ID](const class_A& rhs) -> bool { return rhs.get_id() == ID; } }; 

這里有一個權衡。 在專業方面,您不必為仿函數編寫10行左右的代碼,但在con方面,lambda語法很時髦,需要一些時間來習慣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM