2

我有以下行中定义的 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* 指针)?您能否在下面的功能代码中指出所需的代码片段?我可以删除最后保存在迭代器中的第一个出现。但是,我不确定如何删除其余的事件。谢谢。

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;
}
4

5 回答 5

5

不能保证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改用或存储智能指针,以便您可以使用擦除删除习惯用法(甚至根本不存储指针)。

于 2013-06-14T13:28:00.020 回答
2

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

如果要删除条目并删除它们的内容,则需要完全不同的方法。就像制作原始指针 unique_ptr 一样。

于 2013-06-14T13:27:03.547 回答
2

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

您应该首先在要删除的元素的向量中找到索引,释放它们,然后再进行删除。我建议一个类似的解决方案:1)用于std::find_if查找要删除的第一个元素,2)释放内容并与向量的“最后一个”元素交换指针,3)重复直到std::find_if什么都不返回。在这里,“last”表示最后一个尚未标记为要删除的元素。

于 2013-06-14T13:29:35.717 回答
2

我将提供 2 种替代方法,而不是展示如何正确删除您的元素...

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

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

很简单。包含 2 个指针的一对很小。动态分配该对将会更快,更容易。您也不必担心删除。

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

如果您知道为什么要动态分配,并且知道在这种情况下必须这样做,请使用智能指针 ( unique_ptr)。unique_ptr将自行清理,因此您无需删除任何内容。

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

于 2013-06-14T13:37:04.177 回答
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::vectorwhich 表示其中的指针的所有权,那么将其设置为vector<unique_ptr<>>. 您确实必须删除一些管理内存的代码,将一些代码替换push_backemplace_back,并添加一些.get()调用,然后就可以了。

于 2013-06-14T14:51:07.597 回答