Copying Algorithms

An introduction to the 7 copying algorithms in the C++ standard library: copy(), copy_n(), copy_if(), copy_backward(), reverse_copy(), rotate_copy(), and unique_copy().
This lesson is part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, Unlimited Access
3D Character Concept Art
Ryan McCombe
Ryan McCombe
Updated

In this lesson, we cover the most essential copying algorithms. We’ll cover the seven main algorithms for copying objects from one container to another: copy(), copy_backward(), rotate_copy(), reverse_copy(), copy_if(), copy_n() and unique_copy().

All the algorithms in this section are available within the <algorithm> header:

#include <algorithm>

What it means for an object to be copied is defined by the copy semantics of its type. We cover copy semantics in more detail here:

std::ranges::copy()

The standard copy() algorithm will copy every element from a source range to a new destination. The destination where elements will be copied to is defined by passing an iterator as the second argument.

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

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy(Source, Destination.begin());

  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
1, 2, 3, 0, 0, 0,

We do not need to copy to the beginning of the destination container. We can provide an iterator that points anywhere:

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

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy(Source,
                    Destination.begin() + 2);

  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
0, 0, 1, 2, 3, 0,

We are responsible for ensuring that the location the destination iterator points to has enough space to receive our copies.

Return Type

The type returned from std::ranges::copy() is a std::ranges::in_out_result which is commonly aliased to types like std::ranges::copy_result. This type has two fields:

  • in: An iterator for our input range, pointing at the location where the sentinel was encountered. In the previous example, this is equivalent to Source.end()
  • out: An iterator for our destination, pointing beyond the last element that was copied
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy_result Result{
      std::ranges::copy(Source,
                        Destination.begin())};

  int64_t InputSize{
      std::distance(Source.begin(), Result.in)};

  std::cout << "The input size was " << InputSize;

  int64_t OutputPosition{std::distance(
      Destination.begin(), Result.out - 1)};

  std::cout << "\nThe last element copied is at "
               "position "
            << OutputPosition
            << "\nin the destination";

  std::cout << "\nIts value is "
            << Destination[OutputPosition];
}
The input size was 3
The last element copied is at position 2
in the destination
Its value is 3

The std::ranges::in_out_result type supports structured binding for easier use:

auto [in, out]{std::ranges::copy(
      Source, Destination.begin())};

std::ranges::copy_backward()

The copy_backward() algorithm accepts a source input range, and an iterator pointing at where we want the copies to end.

Elements from the source are copied in reverse order, with the destination iterator also moving in reverse order. The effect of this is that the relative order of the source elements is maintained within the destination:

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

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy_backward(Source,
                             Destination.end());

  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
0, 0, 0, 1, 2, 3,

Return Type

Similar to copy(), the copy_backward() algorithm returns a std::ranges::in_out_result, with the same properties:

  • in - An iterator for the input range, pointing at where the sentinel was triggered. In the previous example, this is equivalent to Source.end()
  • out - An iterator for the destination range, pointing to the last element moved.

Given that elements are copied from right to left, the out iterator will point to the leftmost element that was copied within the destination:

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

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0};

  auto [in, out]{std::ranges::copy_backward(
      Source, Destination.end())};

  std::cout << "Values in Destination: ";
  for (auto& Num : Destination) {
    std::cout << Num << ", ";
  }

  std::cout << "\nThe input had "
            << std::distance(Source.begin(), in)
            << " objects\n";

  std::cout << "The output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *out;
}
Values in Destination: 0, 0, 1, 2, 3,
The input had 3 objects
The output iterator is at position 2
The last element copied was 1

Given copy_backward() traverses our containers in reverse order, it relies on our input range and output iterator supporting bidirectional iteration. For example, we would not be able to use copy_backward() with a std::forward_list, as this container only supports forward iteration.

Why do we need copy_backward()?

It may seem weird that we have both a copy() and copy_backward() algorithm. The reason we have both is to deal with situations where our input and output ranges are overlapping. The most common reason for this is when we’re trying to copy objects to a different location within the same container.

For example, lets imagine we have the collection {1, 2, 3, 0, 0} and we want to copy the 1, 2 and 3 to the location two positions to the right, giving us {1, 2, 1, 2, 3}.

If we try to do this with copy(), we may not get what we want:

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

struct T {/*...*/}; int main() { std::vector<T> Values{ T{1}, T{2}, T{3}, T{0}, T{0}}; std::ranges::copy( Values.begin(), Values.begin() + 3, // Undefined behaviour - this // destination is within the input range Values.begin() + 2); for (T& Object : Values) { std::cout << Object.Value << ", "; } }
1, 2, 1, 2, 1,

This is because the algorithm’s first copy action causes the 1 to overwrite the 3. We hadn’t copied the 3 to its new position yet, and now we’ve lost it. If we use copy_backward() instead, we get the desired result:

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

struct T {/*...*/}; int main() { std::vector<T> Values{ T{1}, T{2}, T{3}, T{0}, T{0}}; std::ranges::copy_backward( Values.begin(), Values.begin() + 3, // This is now valid - the destination is // no longer within the source range Values.end()); for (T& Object : Values) { std::cout << Object.Value << ", "; } }
1, 2, 1, 2, 3,

In general, when using the copy() or copy_backward() algorithm, if the destination iterator is within the source range, the behaviour is undefined. When copying elements to a different location within the same container, we can deal with this by following a simple rule:

  • When copying objects to a position to the right of where they currently are, as was the case in the previous example, use copy_backward()
  • If copying objects to a position to the left of where they currently are, use copy()

std::ranges::reverse_copy()

The reverse_copy algorithm accepts an input range and a destination iterator. The input range is copied from right to left, whilst the destination iterator moves forward. The effect of this is that the source elements are copied into the destination in reverse order:

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

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::reverse_copy(
      Source, Destination.begin());

  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
3, 2, 1, 0, 0, 0,

Return Type

The reverse_copy() algorithm returns a struct with the type std::ranges::in_out_result. This type is aliased to std::ranges::reverse_copy_result. The output has two properties:

  • in - A past-the-end iterator for the input range
  • out - A past-the-end iterator for the copied input range, within the destination range
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 2, 3};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  auto [in, out] = std::ranges::reverse_copy(
      Source, Destination.begin());

  for (auto i : Destination) {
    std::cout << i << ", ";
  }

  std::cout << "\nThe input had "
            << std::distance(Source.begin(), in)
            << " objects\n";

  std::cout << "The output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *(out - 1);
}
3, 2, 1, 0, 0, 0,
The input had 3 objects
The output iterator is at position 3
The last element copied was 1

std::ranges::rotate_copy()

We can think of rotation as shifting everything left or right within a container. Objects that fall off the edge are rotated around to the opposite edge. For example, imagine we had this container:

{1, 2, 3, 4, 5, 6}

Rotating the container by 1 step to the right would result in this:

{6, 1, 2, 3, 4, 5}

Everything moved one step to the right. The 6 had no room to move right, so it rotated around to the start.

The rotate_copy() algorithm combines a rotation and a copy. Elements from a source container are copied to a destination container, in a rotated order. The algorithm has three arguments:

  • The source range where the objects are to be copied from
  • An iterator pointing at the first object we want to copy - ie, this argument controls the amount of rotation
  • An iterator pointing at where we should start copying objects to

Below, we tell rotate_copy() that we want the first object copied to be Source.end() - 1, which is the 6. Therefore, relative to the Source, the Destination receives the copies rotated by one position to the right:

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

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::rotate_copy(Source,
                           Source.end() - 1,
                           Destination.begin());

  std::cout << "-----Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
-----Source: 1, 2, 3, 4, 5, 6,
Destination: 6, 1, 2, 3, 4, 5,

Return Type

The rotate_copy() algorithm returns a struct with the type std::ranges::in_out_result. This type is aliased to std::ranges::rotate_copy_result. The output has two properties:

  • in - An iterator for the input range, pointing at where the sentinel was encountered. In the previous example, it’s equivalent to Source.end()
  • out - An iterator for the output location, pointing beyond the last element that was copied
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0,
                          0, 0, 0, 0};

  auto [in, out]{std::ranges::rotate_copy(
      Source, Source.end() - 1,
      Destination.begin())};

  for (auto i : Destination) {
    std::cout << i << ", ";
  }

  std::cout << "\nThe input had "
            << std::distance(Source.begin(), in)
            << " objects\n";

  std::cout << "The output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *(out - 1);
}
6, 1, 2, 3, 4, 5, 0, 0,
The input had 6 objects
The output iterator is at position 6
The last element copied was 5

std::ranges::copy_n()

The std::ranges::copy_n() algorithm copies a limited number of objects from a source range to a destination range. The function has 3 parameters:

  • An iterator pointing to the beginning of the source range
  • An integer representing how many objects to copy
  • An iterator pointing to the start of the destination range, where objects are to be copied

The "n" in the name of this function relates to the convention of using a variable called "n" to represent a quantity of objects. In this case, the n is the value we pass as the second argument.

We should ensure that the location starting at our source iterator has at least n elements, and that the location starting at our destination iterator has enough space to store them.

Below, we copy 4 elements from our Source to our Destination:

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

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy_n(Source.begin(), 4,
                      Destination.begin());

  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
1, 2, 3, 4, 0, 0,

Return Type

The std::ranges::copy_n() algorithm returns a std::ranges::copy_n_result, which is an alias for std::ranges::in_out_result. This is a struct with two properties:

  • in - an iterator for the input range, pointing beyond the last element copied. In the previous example, this is equivalent to Source.begin() + 4
  • out - an iterator for the output range, pointing beyond the last element copied. In the previous example, this is equivalent to Destination.begin() + 4
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  auto [in, out]{std::ranges::copy_n(
      Source.begin(), 4, Destination.begin())};

  std::cout << "Values in Destination: ";
  for (auto& Num : Destination) {
    std::cout << Num << ", ";
  }

  std::cout
      << "\nThe input iterator is at position "
      << std::distance(Source.begin(), in);

  std::cout << "\nThe output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *(out - 1);
}
Values in Destination: 1, 2, 3, 4, 0, 0,
The input iterator is at position 4
The output iterator is at position 4
The last element copied was 4

std::ranges::copy_if()

The std::ranges::copy_if() algorithm works similarly to std::ranges::copy(), but it accepts a predicate function as the third argument. Each object in the source range will be passed to the predicate, and it will be copied only if that predicate call returns true.

Below, we use std::ranges::copy_if() to copy only the even numbers from the source range:

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

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector<int> Destination;
  Destination.resize(Source.size());

  auto isEven{
      [](const int& x) { return x % 2 == 0; }};

  std::ranges::copy_if(
      Source, Destination.begin(), isEven);

  std::cout << "-----Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
-----Source: 1, 2, 3, 4, 5, 6,
Destination: 2, 4, 6, 0, 0, 0,

Predicates

A function that returns a boolean is sometimes called a predicate. Therefore, isEven() in our previous program is an example of a predicate.

Return Type

The type returned from std::ranges::copy_if() is a std::ranges::in_out_result which is aliased as std::ranges::copy_if_result. This type has two fields:

  • in: An iterator for the input range, pointing to where the sentinel was encountered. In the previous example, it is equivalent to Source.end()
  • out: An iterator within the destination location, pointing beyond the last element copied
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector<int> Destination;
  Destination.resize(Source.size());

  auto isEven{
      [](const int& x) { return x % 2 == 0; }};

  auto [in, out]{std::ranges::copy_if(
      Source, Destination.begin(), isEven)};

  std::cout << "-----Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }

  std::cout << "\nThe input had "
            << std::distance(Source.begin(), in)
            << " objects\n";

  std::cout << "The output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *(out - 1);
}
-----Source: 1, 2, 3, 4, 5, 6,
Destination: 2, 4, 6, 0, 0, 0,
The input had 6 objects
The output iterator is at position 3
The last element copied was 6

Projection Function

The std::ranges::copy_if() algorithm additionally accepts an optional 4th argument, for a projection function. We cover projection in more detail in a dedicated lesson:

Below, we project our Player objects to their level using the GetLevel() member function. This causes our predicate to receive an int, and return true if that integer is greater than 20. The combined effect of this is that our copy_if() invocation copies players if their level is above 20:

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

class Player {/*...*/}; int main() { std::vector<Player> Source; Source.emplace_back("Roderick", 10); Source.emplace_back("Anna", 50); Source.emplace_back("Robert", 100); std::vector<Player> Destination; Destination.resize(Source.size()); auto isOver20{[](int x) { return x > 20; }}; auto [in, out] = std::ranges::copy_if( Source, Destination.begin(), isOver20, &Player::GetLevel); std::cout << "Source: "; for (Player& P : Source) { std::cout << P.GetName() << ", "; } std::cout << "\nCopied: "; for (Player& P : std::ranges::subrange{ Destination.begin(), out}) { std::cout << P.GetName() << ", "; } }
Source: Roderick, Anna, Robert,
Copied: Anna, Robert,

std::ranges::unique_copy()

The unique_copy() algorithm has a fairly niche use. It works similarly to std::ranges::copy(), but will not copy any object that passed an equality check with the previous object.

For example, copying 1, 2, 2, 1 will yield 1, 2, 1. The second 2 is skipped as it was equal to the previous object in the original range. Only the first object in each group of equal objects will be copied. As such, copying 1, 2, 2, 2, 1 will also yield 1, 2, 1.

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

int main() {
  std::vector Source{1, 1, 2, 1, 2, 2, 2, 2};
  std::vector<int> Destination;
  Destination.resize(Source.size());

  std::ranges::unique_copy(Source,
                           Destination.begin());

  std::cout << "-----Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
-----Source: 1, 1, 2, 1, 2, 2, 2, 2,
Destination: 1, 2, 1, 2, 0, 0, 0, 0,

Return Type

The unique_copy() algorithm returns a struct with the type std::ranges::in_out_result. This type is aliased to std::ranges::unique_copy_result. The output has two properties:

  • in - An iterator for the input range, pointing at where the sentinel was found. In the previous example, it is equivalent to Source.end()
  • out - An iterator for the output location, pointing beyond the last object that was copied
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector Source{1, 1, 2, 1, 2, 2, 2, 2};
  std::vector<int> Destination;
  Destination.resize(Source.size());

  auto [in, out]{std::ranges::unique_copy(
      Source, Destination.begin())};

  std::cout << "-----Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }

  std::cout << "\nThe input had "
            << std::distance(Source.begin(), in)
            << " objects\n";

  std::cout << "The output iterator is at "
               "position "
            << std::distance(
                   Destination.begin(), out);

  std::cout << "\nThe last element copied was "
            << *(out - 1);
}
-----Source: 1, 1, 2, 1, 2, 2, 2, 2, 
Destination: 1, 2, 1, 2, 0, 0, 0, 0,
The input had 8 objects
The output iterator is at position 4
The last element copied was 2

Custom Comparison Function

By default, the unique_copy() algorithm uses the equality operator == to determine if adjacent objects are equal. We can control this by passing our own comparison function as an additional argument.

This function will receive two objects from our input, and should return true if the algorithm should consider those objects equal. Below, we use this to treat two objects in our collection as being equal if their absolute value is equal:

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

bool AbsEqual(int x, int y) {
  return std::abs(x) == std::abs(y);
}

int main() {
  std::vector Source{1, -1, -2, 2, 3};
  std::vector<int> Destination;
  Destination.resize(Source.size());

  std::ranges::unique_copy(
    Source, Destination.begin(), AbsEqual);

  std::cout << "Source: ";
  for (auto i : Source) {
    std::cout << i << ", ";
  }

  std::cout << "\nDestination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
Source: 1, -1, -2, 2, 3,
Destination: 1, -2, 3, 0, 0,

Projection Function

The unique_copy() algorithm allows us to provide a projection function. Our objects will be passed to this projection function, and what that function returns will be used to determine whether the original objects are equal.

Below, we want to consider two Player objects to be equal if they have the same Name. So, we use the GetName member function to cause the comparison function to receive those names, instead of the full Player objects.

We want to use the default comparison function - the == operator - so we pass {} as the third argument. In this case, it will specifically use the == operator on std::string, as our projection function is returning std::string objects:

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

class Player {/*...*/}; int main() { std::vector<Player> Source; Source.emplace_back("Roderick", 10); Source.emplace_back("Anna", 50); Source.emplace_back("Anna", 50); Source.emplace_back("Robert", 100); Source.emplace_back("Robert", 100); std::vector<Player> Destination; Destination.resize(Source.size()); auto [in, out] = std::ranges::unique_copy( Source, Destination.begin(), {}, &Player::GetName); std::cout << "Source: "; for (Player& P : Source) { std::cout << P.GetName() << ", "; } std::cout << "\nCopied: "; for (Player& P : std::ranges::subrange{ Destination.begin(), out}) { std::cout << P.GetName() << ", "; } }
Source: Roderick, Anna, Anna, Robert, Robert,
Copied: Roderick, Anna, Robert,

Using Iterator-Sentinel Pairs

Our previous examples tended to provide our range as a single argument but, as usual, we can instead provide it as an iterator-sentinel pair. Below, we use this technique to copy only a subset of the objects within our collection:

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

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::ranges::copy(Source.begin() + 1,
    Source.end() - 1, Destination.begin());

  std::cout << "Destination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
Destination: 2, 3, 4, 5, 0, 0,

Using Iterator-Based Algorithms

In this lesson, we’re focusing on the versions of these algorithms that work with ranges, a C++20 feature.

Alternative versions of these algorithms work directly with iterators. These alternative functions are also in the <algorithm> library and can be used by excluding the ranges namespace from our identifier.

Below, we rewrite the first example to use std::copy() instead of std::ranges::copy(). Instead of passing the source as a range, we pass two iterators, representing the first and last element to copy:

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

int main() {
  std::vector Source{1, 2, 3, 4, 5, 6};
  std::vector Destination{0, 0, 0, 0, 0, 0};

  std::copy(Source.begin() + 1,
    Source.end() - 1, Destination.begin());

  std::cout << "Destination: ";
  for (auto i : Destination) {
    std::cout << i << ", ";
  }
}
Destination: 2, 3, 4, 5, 0, 0,

Compared to their more modern range-based counterparts, these variations have three disadvantages:

  • We must provide our input as two arguments - we don’t have the option of providing a container directly
  • The end of our input be provided as an iterator, rather than the more flexible sentinel option of the range-based algorithms
  • They do not support projection functions

However, they remain in common use, and are usually our best options when working on projects targeting specifications prior to C++20.

Summary

In this lesson, we introduced various std::ranges algorithms for copying elements within and between containers. Here are the main points students learned:

  • The basic usage of std::ranges::copy() for copying elements from a source range to a destination.
  • How to use std::ranges::copy_backward() for copying elements in reverse order, useful for handling overlapping ranges.
  • Using std::ranges::reverse_copy() to invert the order of elements during the copy process.
  • Using std::ranges::rotate_copy() to perform rotation operations combined with copying, to shift elements.
  • The std::ranges::copy_n() algorithm for copying a specified number of elements from one range to another.
  • The selective copying of elements based on a predicate using std::ranges::copy_if(), including the use of predicates and projection functions.
  • Employing std::ranges::unique_copy() to copy elements while omitting consecutive duplicates, with options for custom comparison and projection functions.
  • Using iterator-sentinel pairs for specifying ranges in copy operations.
  • Differences between iterator-based and range-based copy algorithms, including the limitations of the older iterator-based techniques.

Was this lesson useful?

Next Lesson

Removal Algorithms

An overview of the key C++ standard library algorithms for removing objects from containers. We cover remove(), remove_if(), remove_copy(), and remove_copy_if().
3D Character Concept Art
Ryan McCombe
Ryan McCombe
Updated
A computer programmer
This lesson is part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, Unlimited Access
Standard Library Algorithms
Next Lesson

Removal Algorithms

An overview of the key C++ standard library algorithms for removing objects from containers. We cover remove(), remove_if(), remove_copy(), and remove_copy_if().
3D Character Concept Art
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved