2

次の行で定義されている std::vector インスタンスがあります。

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

基礎となる std::pair オブジェクトの最初の項目はサブスクライバー エンティティのネットワーク アドレスであり、2 番目の項目はサブスクライブされたエンティティのネットワーク アドレスです。したがって、std::pair オブジェクトは、ここではサブスクリプションを、サブスクライバーとサブスクライブされたエンドポイント アドレスのペアとして表します。

特定のサブスクライバー エンドポイント アドレスについて、このベクター内のすべてのサブスクリプションを削除したいと考えています。この目的のために、述語で std::remove_if を使用する指定された関数を以下に記述しました。std::remove_if のドキュメントに基づいて、私の理解では、 std::remove_if は削除されるすべての出現をベクトルの最後に置き、ベクトルの最後を新しい位置に後方に移動します。

私の質問は次のとおりです。

これらの std::pair アイテムは、remove_if の呼び出し後にベクターの最後に配置され、コンテンツを 1 つずつ動的に割り当て解除します (つまり、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

おそらく代わりにスマート ポインターを使用するか、スマート ポインターを保存して、 erase-remove イディオムstd::partitionを使用できるようにする必要があります(または、ポインターをまったく保存しないこともできます)。

于 2013-06-14T13:28:00.020 に答える
2

ドキュメントを正しく理解していれば(「削除は、消去する要素が上書きされるように、範囲内の要素をシフトすることで行われます」)、削除する必要がある要素が上書きされるため、その動的コンテンツは削除できません。消去する要素へのポインターを失います。

削除する要素のベクトル内のインデックスを最初に見つけて、それらの割り当てを解除し、後で削除を行う必要があります。これに似た解決策を提案します:1)std::find_if削除する最初の要素を見つけるために使用し、2)コンテンツの割り当てを解除し、ポインターをベクターの「最後の」要素と交換し、3)std::find_if何も返さないまで繰り返します。ここで「最後」とは、まだ削除フラグが立てられていない最後の要素を意味します。

于 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 に答える
2

その削除は何をすることになっていますか?最後に..endには、コンテンツがその前にベクターにコピーされた「廃止された」要素のゴミが含まれています。確かに、ht lambda で delete を使用して範囲で for_each を呼び出すことができますが、それが賢明な結果をもたらすとは思えません。

エントリを削除し、そのコンテンツも削除する場合は、まったく異なるアプローチが必要です。代わりに生のポインター unique_ptr を作成するように。

于 2013-06-14T13:27:03.547 に答える
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<unique_ptr<>>です。メモリを管理する一部のコードを削除し、一部push_backをに置き換え、いくつかの呼び出しemplace_backを追加する必要があります。.get()

于 2013-06-14T14:51:07.597 に答える