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

3

我有一个std::vector实例,如下所示:

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

在底层的 std::pair 对象中,第一个项目是订阅方实体的网络地址,而第二个项目是被订阅方实体的网络地址。因此,std::pair 对象在这里表示订阅作为订阅者和被订阅端点地址的一对。
我想删除给定订阅者端点地址在该向量中的所有订阅。为此,我编写了下面指示的函数,其中我使用具有谓词的 std::remove_if。根据 std::remove_if 的文档,我的理解是 std::remove_if 将要删除的所有出现都放在向量的末尾,并将向量的末尾向后移动到其新位置。
我的问题是:如何才能到达在调用 remove_if 后放入向量末尾的这些 std::pair 项,以便逐个动态释放它们的内容(即释放 std::pair* 指针)?您能否在下面的函数代码中指示所需的代码片段?我可以删除保留在迭代器 last 中的第一个出现。但是,我不确定如何删除其余出现。谢谢。
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;
}

1
你应该真的考虑使用 shared_ptr 或 unique_ptr。 - undefined
我觉得最好不要动态分配std::pair,而是将其作为非指针变量赋值给向量。这样对现有代码的影响会更小。感谢大家的回答... - undefined
5个回答

6

无法保证remove_if将删除的元素放置在向量末尾:范围[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,或存储智能指针,这样您就可以使用擦除-移除范式(甚至完全不存储指针)。


为什么这些元素具有未指定的值?! - undefined
1
@Dave:因为remove_if的目标是删除元素,而不是将它们与范围中的其他元素分离。因此,该算法假设被删除的元素之后不需要再访问。 - undefined

2

这个delete语句的作用是什么?最后.. end中包含了一个名为'obsolete'的元素垃圾桶,其中的内容在拷贝到向量之前。当然,你可以在带有delete的lambda范围上调用for_each,但我怀疑这会得到明智的结果。

如果您想删除条目并删除它们的内容,需要完全不同的方法。例如,将原始指针unique_ptr化。


2
我将提供2个替代方案,而不是展示如何正确删除您的元素...
最佳解决方案:不要动态分配该对:
std::vector 非常简单。包含2个指针的对是微小的。这样做会更快,更容易,不需要担心删除。
可接受的解决方案:使用unique_ptr:
如果您知道为什么要动态分配,并且知道在这种情况下必须这样做,请使用智能指针(unique_ptr)。unique_ptr将自行清理,因此您不需要删除任何内容。
std::vector>

2
如果我理解正确文档(“通过移动范围内的元素来执行删除,以覆盖要删除的元素”),则需要删除的元素将被覆盖,因此无法删除其动态内容,因为您会失去指向要删除的元素的指针。
您应该首先找到要删除的元素在向量中的索引,对它们进行释放,然后再进行删除。我建议使用类似于以下的解决方案:1)使用std::find_if查找要删除的第一个元素,2)释放内容并与您的向量中的“最后一个”元素交换指针,3)重复直到std::find_if返回为空。这里,“last”表示尚未标记为要删除的最后一个元素。

0
首先,写下 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>`几乎是一种无痛的替换方法。你需要删除一些管理内存的代码,将一些`push_back`替换为`emplace_back`,并添加一些`.get()`调用,就这样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接