2016-12-20 7 views
2

私は約10MBのパケットを指し示すポインターのベクトルを持っています。そこでは、最初の2MBから、私は自分の述語と一致するものをすべて削除したいと思っています。ここで問題となるのはremove_ifですが、私の使用例では不要ですが、ベクトル全体を繰り返し処理します。他の効率的な方法はありますか?上記のコードでC++ remove_if全体のベクトルを反復せずに

fn_del_first_2MB 
{ 
    uint32 deletedSoFar = 0; 
    uint32 deleteLimit = 2000000; 

    auto it = std::remove_if (cache_vector.begin(), cache_vector.end(),[deleteLimit,&deletedSoFar](const rc_vector& item){ 
    if(item.ptr_rc->ref_count <= 0) { 
     if (deletedSoFar < deleteLimit) { 
      deletedSoFar += item.ptr_rc->u16packet_size; 
     delete(item.ptr_rc->packet);  
     delete(item.ptr_rc); 
      return true; 
     } 
     else  
      return false; 
    } 
    else 
     return false; 
    }); 
    cache_vector.erase(it, cache_vector.end()); 
} 

deletedSoFardeleteLimitより大きくなると、それ以上の任意の繰り返しは不要です。

+1

代わりに 'cache_vector.end()'独自のマーカーを置くの。さまざまな[std :: remove_if](http://en.cppreference.com/w/cpp/algorithm/remove)オーバーロードがあります。 –

+0

@ RawN ^これは、簡潔なコードサンプルでは適切な答えかもしれません。 –

+0

@πάντεῥεῖ私は*簡潔なコードサンプル*部分が欠けています。私はMeyersの最初の本の半分だけです。 –

答えて

1

あなたがあなた自身のループを使用することがあります。

void fn_del_first_2MB() 
{ 
    const uint32 deleteLimit = 2000000; 

    uint32 deletedSoFar = 0; 
    auto dest = cache_vector.begin(); 
    auto it = dest 

    for (; it != cache_vector.end(); ++it) { 
     const auto& item = *it; 

     if (item.ptr_rc->ref_count <= 0) { 
      deletedSoFar += item.ptr_rc->u16packet_size; 
      delete(item.ptr_rc->packet);  
      delete(item.ptr_rc); 
      if (deletedSoFar >= deleteLimit) { 
       ++it; 
       break; 
      } 
     } else if (dest != it) { 
      *dest = std::move(*it); 
      ++dest; 
     } 
    } 
    cache_vector.erase(dest, it); 
} 
+0

これは最適な解決策だと思われますが、私が試してみるといくつかの問題で終わります。しかし、あなたの時間をありがとう。 'バックトレース: /system/lib/libc.so(je_arena_dalloc_bin_locked + 221) /system/lib/libc.so(je_tcache_bin_flush_small + 238) /system/lib/libc.so(IFREE + 448) /システム/lib/libc.soを(10 +フリー) /system/lib/smu/libwlan_core.so(_ZN15roam_scan_cache23roam_cache_delete_frontEj + 220) /system/lib/smu/libwlan_core.so(_ZN15roam_scan_cache21roam_packet_processorEPv + 660) /システム/ LIB/libcの.so(_ZL15__pthread_startPv + 30) /system/lib/libc.so(__start_thread + 6) ' – Ananth

+1

@Ananth:私は' break 'の直前に '++ it' – Jarod42

1

std::remove_if()は、第2引数として.end()イテレータを渡す必要はありません。第1引数が増分で第2引数に到達できる限り、どのイテレータも渡すことができます。

これまでに遭遇した要素の累積サイズによって条件が異なるため、やや複雑です。結果として、std::remove_if()が使用されないように見えます。このような何か動作するはずです(私はそれが述語を変え続けるようstd::find_if()のこの使用は、実際に合法であるかはわからないが):

std::size_t accumulated_size(0u); 
auto send(std::find_if(cache_vector.begin(), cache_vector.end(), 
           [&](rc_vector const& item) { 
     bool rc(accumulated_size < delete_limit); 
     accumulated_size += item.ptr_rc->u16packet_size; 
     return rc; 
    }); 
std::for_each(cache_vector.begin(), send, [](rc_vector& item) { 
     delete(item.ptr_rc->packet);  
     delete(item.ptr_rc); 
    }); 
cache_vector.erase(cache_vector.begin(), send); 

std::for_each()も同様std::find_if()の使用に折り畳むことができますが、私は好みます物事を論理的に分離しておく。充分に大きなシーケンスの場合、メモリをキャッシュに2回転送する必要がある場合、パフォーマンスの差が生じる可能性があります。引用された小さな数字のために、私はその違いが測定できることを疑う。

+0

OPの 'if(item.ptr_rc-> ref_count <= 0)'の状態を忘れてしまいます。そして、「消去」はもっと複雑です。 – Jarod42

3

cache_vector.end()の代わりに、独自のイテレーターマーカーmyIterを入れます。 remove_ifオプションを使用する場合は、erase-removeイディオムに従ってください。ここでは最初の4つの要素に影響を与えている例:

#include <iostream> 
#include <vector> 
#include <algorithm> 

int main() 
{ 
    std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
    size_t index = 4; // index is something you need to calculate 
    auto myIter = vec.begin() + index; // Your iterator instead of vec.end() 
    vec.erase(std::remove_if(vec.begin(), myIter, [](int x){return x < 3; }), myIter); 
    // modified vector: 
    for (const auto& a : vec) 
    { 
     std::cout << a << std::endl; 
    } 
    return 0; 
} 
+0

ありがとうございますが、この場合、実行時にmyIterを計算する必要があります。つまり、myIterを見つけて実際に消去を実行する必要があります。 – Ananth

関連する問題