std::remove_if:从std::vector中移除所有出现的指针

std::remove_if: Removing all occurences of a pointer from std::vector

本文关键字:std 指针 remove if vector      更新时间:2023-10-16

我有一个std::vector实例,定义如下行:

std::vector< std::pair<EndPointAddr*, EndPointAddr*>* > mServiceSubscriptionsList;

底层std::pair对象中的第一项是订阅实体的网络地址,第二项是订阅实体的网络地址。因此,std::pair对象在这里将订阅表示为一对订阅者和被订阅者端点地址。

我想删除此向量中给定订阅者端点地址的所有订阅。为此,我编写了下面指示的函数,其中我使用std::remove_if和谓词。根据std::remove_if的文档,我的理解是std::remove_if将所有要删除的内容放到vector的末尾,并将vector的末尾向后移动到它的新位置。

我的问题是

我怎样才能到达这些std::pair项,在调用remove_if之后放入vector的末尾,以便逐个动态地释放它们的内容(即删除std::pair*指针)?你能在下面的函数代码中指出需要的代码片段吗?我可以删除最后保存在迭代器中的第一个项。但是,我不确定如何删除其余的事件。谢谢。

bool 
XXX::removeSubscriptionForASpecificSubscriber(EndPointAddr * ptrSubscriberAddr)
{
  auto last = 
       std::remove_if(mServiceSubscriptionsList.begin(),
                      mServiceSubscriptionsList.end(),
                      [ptrSubscriberAddr](std::pair<EndPointAddr*, EndPointAddr*>*  thePair) 
                      { 
                         return ptrSubscriberAddr->getXXXAddress().compareTo(thePair->first->getXXXAddress());
                      });
 if(last != mServiceSubscriptionsList.end())
 {
   //HERE I CAN DELET THE FIRST OCCURENCE, but WHAT I WANT IS TO DELETE ALL OCCURANCES
   if(*last != nullptr)
   { 
     delete *last;
   }
   mServiceSubscriptionsList.erase(last, mServiceSubscriptionsList.end());
   return true;
 }
 return false;
}

不能保证remove_if将擦除的元素放在vector的末尾:[newEnd, oldEnd)范围内的迭代器是可解引用的,但这些元素具有未指定的值。

例如,以下代码

std::vector<int> v { 0, 1, 2, 3, 4 };
auto new_end = std::remove_if(v.begin(), v.end(), is_odd);

可以修改v,使其包含

0, 2, 4, 3, 4
         ^
       newEnd

您可能应该使用std::partition,或者存储智能指针,以便您可以使用擦除-删除习惯用法(甚至根本不存储指针)。

这个删除应该做什么?最后..end包含"过时的"元素垃圾,其内容被复制到它之前的向量。当然,您可以在ht lambda中调用带有delete的范围上调用for_each,但我怀疑这会得到合理的结果。

如果您想要删除条目并删除其内容,则需要完全不同的方法。比如把原始指针改成unique_ptr

如果我正确理解了文档("删除是通过移动范围内的元素来完成的,要删除的元素被覆盖"),您需要删除的元素被覆盖,因此您无法删除其动态内容,因为您丢失了指向要删除的元素的指针。

您应该首先找到要删除的元素的vector中的下标,然后释放它们,然后再进行删除。我建议一个类似的解决方案:1)使用std::find_if找到要删除的第一个元素,2)释放内容并与向量的"最后"元素交换指针,3)重复直到std::find_if没有返回任何内容。这里,"last"是指最后一个尚未被标记为要删除的元素。

我将提供两种替代方法,而不是展示如何正确删除元素…

最佳解决方案:不要动态分配pair:

std::vector<std::pair<EndPointAddr*, EndPointAddr*>>

相当简单。包含两个指针的pair是很小的。而不是动态地分配那对会更快、更容易。你也不需要担心删除。

可接受的解决方案:使用unique_ptr:

如果你知道为什么动态分配,并且知道在这种情况下你必须这样做,使用智能指针(unique_ptr)。unique_ptr会自己清理,所以你不需要删除任何东西。

std::vector<std::unique_ptr<std::pair<EndPointAddr*, EndPointAddr*>>>

首先写erase_remove_if:

template<typename Container, typename Lambda>
Container&& erase_remove_if( Container&& c, Lambda&& closure ) {
  using std::begin; using std::end;
  auto new_end = std::remove_if( begin(c), end(c), std::forward<Lambda>(closure) );
  c.erase(new_end, end(c));
  return std::forward<Container>(c);
}

第二,擦除remove_if谓词中的数据:

bool removeSubscriptionForASpecificSubscriber(EndPointAddr * ptrSubscriberAddr)
{
  erase_remove_if( mServiceSubscriptionsList, 
    [ptrSubscriberAddr](std::pair<EndPointAddr*, EndPointAddr*>*  thePair) 
    {
      if (ptrSubscriberAddr->getXXXAddress().compareTo(thePair->first->getXXXAddress()))
      {
        delete ptrSubscriberAddr;
        return true;
      } else {
        return false;
      }
    });
  return true;
}

如果你不想使用std::unique_ptr来存储指针对。请注意,如果您有一个std::vector,它表示指针的所有权,那么将其更改为vector<unique_ptr<>>实际上是一个几乎没有痛苦的临时修复。您必须删除一些管理内存的代码,将一些push_back替换为emplace_back,并添加一些.get()调用,然后它。