Подтвердить что ты не робот

Я использую copy_if неправильно?

Я использую visual studio 2010, и я пытаюсь использовать std:: copy_if, Я хочу скопировать все значения, удовлетворяющие предикату. Например:

struct comp
{
    bool operator()(const int i) { return i == 5 || i == 7; }
};

int main()
{
    array<int, 10> arr =  { 3, 2, 5, 7, 3, 5, 6, 7 };
    vector<int> res;
    copy_if(arr.begin(), arr.end(), res.begin(), comp());

    for(int i = 0; i < res.size(); i++)
    {
        cout << res[i] << endl;
    }

    return 0;
}

Но когда я запускаю этот код, я получаю: векторный итератор не увеличивается.

4b9b3361

Ответ 1

Алгоритм copy_if выглядит примерно так (взято из MSVC2010):

template<class InIt, class OutIt, class Pr> inline
OutIt copy_if(InIt First, InIt Last, OutIt Dest, Pr Pred)
{
    for (; First != _Last; ++First)
        if (Pred(*_First))
            *Dest++ = *First;
    return (Dest);
}

И как вы можете видеть, copy_if не делает push_back, он просто копирует значение в позиции, где находится итератор, а затем увеличивает итератор. Вместо этого вы хотите использовать std:: back_inserter, который выталкивает элемент обратно вашего вектора. И если вы используете MSVC2010, вы можете использовать Lambda вместо объекта функции, который Microsoft предлагает как расширение (С++ 0x)

int main()
{
    array<int, 10> arr =  { 3, 2, 5, 7, 3, 5, 6, 7 };
    vector<int> res;
    copy_if(arr.begin(), arr.end(), back_inserter(res),[](const int i) { return i == 5 || i == 7; });

    for(unsigned i = 0; i < res.size(); i++)
        cout << res[i] << endl;

    return 0;
}

Ответ 2

Вы можете использовать итератор вывода:

copy_if(arr.begin(), arr.end(), std::back_inserter(res), comp());

Ответ 3

Если первична проблема, рассмотрите вместо использования std:: back_inserter для заполнения целевого вектора (подход, который включает в себя произвольное количество дорогостоящих переадресаций назначения вектора), вызовите std:: copy_if с указанным целевым вектором источника by dest.erase(iteratorReturnedByCopyIf, dest.end()) - подход, который включает в себя одно распределение спереди, а затем одно перераспределение для erase().

Данные

С++ std:: copy_if производительность с помощью алгоритма дешифрования

код

#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

long long MeasureMilliseconds(std::function<void()> func, unsigned iterations)
{
   auto beginTime = std::chrono::high_resolution_clock::now();
   for (unsigned i = 0; i < iterations; ++i)
   {
      func();
   }
   auto endTime = std::chrono::high_resolution_clock::now();
   long long milliseconds = std::chrono::duration_cast<
      std::chrono::milliseconds>(endTime - beginTime).count();
   return milliseconds;
}

bool IsEven(int i)
{
   return i % 2 == 0;
}

int main()
{
   const unsigned Iterations = 300000;
   for (size_t N = 0; N <= 100; N += 2)
   {
      std::vector<int> source(N);
      // Populate source with 1,2,...,N
      std::iota(std::begin(source), std::end(source), 1);

      long long backInserterMilliseconds = MeasureMilliseconds([&]
      {
         std::vector<int> dest;
         std::copy_if(std::begin(source), std::end(source), 
            std::back_inserter(dest), IsEven);
      }, Iterations);

      long long sourceSizeAndEraseMilliseconds = MeasureMilliseconds([&]
      {
         std::vector<int> dest(source.size());
         std::vector<int>::iterator copyIfIterator = std::copy_if(
            std::begin(source), std::end(source), std::begin(dest), IsEven);
         dest.erase(copyIfIterator, dest.end());
      }, Iterations);

      std::cout << "N=" << N << '\n';
      std::cout << "Default-size dest and back_inserter: " << 
         backInserterMilliseconds << '\n';
      std::cout << "      Source-sized dest and erase(): " << 
         sourceSizeAndEraseMilliseconds << "\n\n";
   }
   return 0;
}

Вывод кода

N=90
Default-size dest and back_inserter: 469
      Source-sized dest and erase(): 89

N=92
Default-size dest and back_inserter: 472
      Source-sized dest and erase(): 90

N=94
Default-size dest and back_inserter: 469
      Source-sized dest and erase(): 92

N=96
Default-size dest and back_inserter: 478
      Source-sized dest and erase(): 92

N=98
Default-size dest and back_inserter: 471
      Source-sized dest and erase(): 93

N=100
Default-size dest and back_inserter: 480
      Source-sized dest and erase(): 92

Ссылки

[alg.copy]
Qt ScatterChart

Ответ 4

Зарезервируйте размер массива. hidayat дает причину этого.

res.resize(arr.size());