2

这是我第一次使用列表 STL,我不确定我想要做的事情是否可行。我有一个包含 class_A 列表的 class_B,我需要 class_B 中的一个函数,它接受一个 ID,在列表中搜索具有相同 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 复制元素还是通过其他方式完成的?)。

无用 的答案对我来说是最有帮助的(非常感谢),是的,我应该使用对指针的引用,因为我打算更改它。

4

3 回答 3

9

你应该这样写:

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成员函数。

于 2012-05-30T17:54:35.383 回答
3
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;
}   

Nowpointer2A通过引用传递,所以调用者的副本在你的函数中被修改。

顺便说一句,您可以class_A * & pointer2A从右到左阅读参数声明,因为“pointer2A 是对指向 class_A 的指针的引用”。

于 2012-05-30T18:01:26.207 回答
1

如果你有一个iterator,你可以通过简单地取消引用迭代器(它给你一个引用),然后获取它的地址(它给你一个指针)来获得一个原始指针。所以,在你的情况下:

pointer2A = &*i;

这似乎是一种奇怪、笨拙的获取指针的方法,但确实如此。但是,当您使用来自 Std Lib 的集合和迭代器时,您通常不关心指针。迭代器是将“STL”粘合在一起的粘合剂。总的来说,这就是您应该处理的问题,而不是原始指针。

您在上面编写的循环肯定可以完成您希望完成的工作,但是有更好的*方法来实现相同的目标。(更好是一个主观术语。)特别是,<algorithm>图书馆提供了两者std::find,并且std::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 行左右的代码,但在另一方面,lambda 语法很时髦,需要一点时间来适应。

于 2012-05-30T18:13:01.177 回答