Spec-Zone.ru › C++

std::copy, std::copy_if

Объявлено в заголовочном файле <algorithm>
template< class InputIt, class OutputIt >
OutputIt copy( InputIt first, InputIt last,
               OutputIt d_first );
(1) (constexpr начиная с C++20)
template< class InputIt, class OutputIt, class UnaryPred >
OutputIt copy_if( InputIt first, InputIt last,
                  OutputIt d_first, UnaryPred pred );
(2) (constexpr начиная с C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2 >
ForwardIt2 copy( ExecutionPolicy&& policy,
                 ForwardIt1 first, ForwardIt1 last,
                 ForwardIt2 d_first );
(3) (начиная с C++17)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class UnaryPred >
ForwardIt2 copy_if( ExecutionPolicy&& policy,
                    ForwardIt1 first, ForwardIt1 last,
                    ForwardIt2 d_first, UnaryPred pred );
(4) (начиная с C++17)

Копирует элементы исходного диапазона [first, last) в целевой диапазон, начинающийся с d_first.

1) copy копирует все элементы исходного диапазона, начиная с first и продвигаясь к last.
Если d_first находится в исходном диапазоне, поведение не определено.
2) copy_if копирует только те элементы исходного диапазона, для которых предикат pred возвращает true, начиная с first и продвигаясь к last.
Если исходный и целевой диапазоны перекрываются, поведение не определено.
3,4) Аналогично (1,2), но порядок копирования определяется policy.
Эти перегрузки участвуют в разрешении перегрузки, только если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с C++20)
Если исходный и целевой диапазоны перекрываются, поведение не определено.

Параметры

first, last - пара итераторов, задающих исходный диапазон
d_first - начало целевого диапазона
pred - унарный предикат, возвращающий ​true для требуемых элементов.

Выражение pred(v) должно преобразовываться в bool для каждого аргумента v типа (возможно, const) VT, где VT — тип значения InputIt, независимо от категории значения, и не должно изменять v. Таким образом, тип параметра VT&не допускается, как и VT, если только для VT перемещение не эквивалентно копированию(начиная с C++11). ​

policy - политика выполнения, которую следует использовать
Требования к типам
-InputIt должен соответствовать требованиям LegacyInputIterator.
-OutputIt должен соответствовать требованиям LegacyOutputIterator.
-ForwardIt1, ForwardIt2 должен соответствовать требованиям LegacyForwardIterator.
-UnaryPred должен соответствовать требованиям Predicate.

Возвращаемое значение

Итератор, указывающий на конец целевого диапазона.

Сложность

Пусть \(\scriptsize N\)N — std::distance(first, last):

1,3) Ровно \(\scriptsize N\)N операций присваивания.
2,4) Ровно \(\scriptsize N\)N применений pred и не более \(\scriptsize N\)N операций присваивания.

Исключения

3,4) В процессе выполнения:
  • Если временные ресурсы памяти, необходимые для распараллеливания, недоступны, выбрасывается std::bad_alloc.
  • Если при доступе к объектам через аргумент алгоритма возникает неперехваченное исключение, поведение определяется политикой выполнения (для стандартных политик вызывается std::terminate).

Примечания

На практике реализации std::copy избегают множественных операций присваивания и используют функции массового копирования, такие как std::memmove, если тип значения является TriviallyCopyable, а типы итераторов удовлетворяют требованиям LegacyContiguousIterator.

При копировании перекрывающихся диапазонов std::copy подходит для копирования влево (начало целевого диапазона находится за пределами исходного диапазона), а std::copy_backward — для копирования вправо (конец целевого диапазона находится за пределами исходного диапазона).

std::copy_if является стабильным алгоритмом. Относительный порядок копируемых элементов сохраняется.

При использовании перегрузок параллельного алгоритма возможны потери производительности, если тип значения ForwardIt1 не является MoveConstructible.

Возможная реализация

copy
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last,
              OutputIt d_first)
{
    for (; first != last; (void)++first, (void)++d_first)
        *d_first = *first;
    
    return d_first;
}
copy_if
template<class InputIt, class OutputIt, class UnaryPred>
OutputIt copy_if(InputIt first, InputIt last,
                 OutputIt d_first, UnaryPred pred)
{
    for (; first != last; ++first)
        if (pred(*first))
        {
            *d_first = *first;
            ++d_first;
        }
    
    return d_first;
}

Пример

В следующем коде std::copy используется как для копирования содержимого одного std::vector в другой, так и для вывода полученного std::vector.

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

int main()
{
    std::vector<int> from_vector(10);
    std::iota(from_vector.begin(), from_vector.end(), 0);    
    std::vector<int> to_vector;
    std::copy(from_vector.begin(), from_vector.end(), std::back_inserter(to_vector));
    
// or, alternatively,
//  std::vector<int> to_vector(from_vector.size());
//  std::copy(from_vector.begin(), from_vector.end(), to_vector.begin());
// either way is equivalent to
//  std::vector<int> to_vector = from_vector;
    
    std::cout << "to_vector contains: ";
    std::copy(to_vector.begin(), to_vector.end(),
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    
    std::cout << "odd numbers in to_vector are: ";
    std::copy_if(to_vector.begin(), to_vector.end(),
                 std::ostream_iterator<int>(std::cout, " "),
                 [](int x) { return x % 2 != 0; });
    std::cout << '\n';
    
    std::cout << "to_vector contains these multiples of 3: ";
    to_vector.clear();
    std::copy_if(from_vector.begin(), from_vector.end(),
                 std::back_inserter(to_vector),
                 [](int x) { return x % 3 == 0; });
    
    for (const int x : to_vector)
        std::cout << x << ' ';
    std::cout << '\n';
}

Возможный результат:

to_vector contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in to_vector are: 1 3 5 7 9
to_vector contains these multiples of 3: 0 3 6 9

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющих поведение, были ретроактивно применены к ранее опубликованным стандартам C++.

DR Применяется к Опубликованное поведение Корректное поведение
LWG 2039 C++11 возвращаемое значение std::copy_if не было указано указано
LWG 2044 C++11 стабильность std::copy_if не была определена определена

См. также

ranges::copyranges::copy_if
(C++20)(C++20)
копирует диапазон элементов в новое место
(объект-функция алгоритма)
copy_backward
копирует диапазон элементов в обратном порядке
(шаблон функции и объект-функция алгоритма)
ranges::copy_backward
(C++20)
reverse_copy
создаёт копию диапазона в обратном порядке
(шаблон функции и объект-функция алгоритма)
ranges::reverse_copy
(C++20)
copy_n
(C++11)
копирует заданное количество элементов в новое место
(шаблон функции и объект-функция алгоритма)
ranges::copy_n
(C++20)
fill
присваивает заданное значение копированием каждому элементу диапазона
(шаблон функции и объект-функция алгоритма)
ranges::fill
(C++20)
remove_copyremove_copy_if
копирует диапазон элементов, исключая элементы, удовлетворяющие заданным критериям
(шаблон функции и объект-функция алгоритма)
ranges::remove_copyranges::remove_copy_if
(C++20)(C++20)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/copy

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API