【问题标题】:how to convert iterator of list STL to instance (C++)如何将列表 STL 的迭代器转换为实例(C++)
【发布时间】:2012-06-05 00:03:24
【问题描述】:

这是我第一次使用列表 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;
}

如何执行此操作,是否可以从迭代器转换为实例?

编辑:

我在多线程程序中使用此函数,我无法将迭代器返回给调用函数,因为另一个线程可能会删除列表中的元素。

现在我有一个指向我的元素的指针(假设它已被锁定,因此无法删除),并且另一个线程删除了另一个元素并对列表执行了排序,指针 I' 会发生什么米控股? (我不知道列表是如何重新排列元素的,是通过使用 copy c'tor 复制元素还是通过其他方式完成的?)。

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

【问题讨论】:

  • 注意(*i).get_id()更容易表达为i-&gt;get_id()
  • 另外,在这种情况下,您不需要“实例”,而是要将迭代器转换为指针。相反,我建议将typedef std::list&lt;class_A&gt;::iterator A_iterator 添加到class_B,然后将pointer2A 设为A_iterator 类型。

标签: c++ list stl


【解决方案1】:

你应该这样写:

pointer2A= &*i;

这里*i 返回的对象的地址可以通过将&amp; 前置为:&amp;*i

请注意,i&amp;*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 成员函数。

【讨论】:

  • 在最后一个示例中,std::find_if 返回一个迭代器,但您使用它初始化 ptr。这不会失败吗?
【解决方案2】:
if(i->get_id()==ID) {
    pointer2A=&*i;
    return true;
}

迭代器被设计为具有与指针相似的语义,因此例如您可以编写i-&gt;get_id(),就像您有一个指向 A 的指针一样。

同样,*i 产生一个引用 A&amp;,而&amp;*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 * &amp; pointer2A,因为“pointer2A 是对指向 class_A 的指针的引用”。

【讨论】:

    【解决方案3】:

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

    pointer2A = &*i;
    

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

    您在上面编写的循环当然可以完成您希望完成的工作,但是还有更好的*方法可以实现相同的目标。 (更好是一个主观术语。)特别是,&lt;algorithm&gt; 库提供了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 行左右的代码,但另一方面,lambda 语法很时髦,需要一点时间来适应。

    【讨论】:

      猜你喜欢
      • 2020-11-06
      • 1970-01-01
      • 2019-03-09
      • 2012-04-24
      • 1970-01-01
      • 2012-11-05
      • 1970-01-01
      • 1970-01-01
      • 2021-09-04
      相关资源
      最近更新 更多