Transferring Data Ranges
The std::copy utility facilitates moving elements from a source range to a destination sequence. It operates across various container types, including arrays and dynamic structures like std::vector.
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
int main() {
std::vector<int> source_data = {10, 20, 30};
std::vector<int> target_storage(source_data.size());
// Move data from source to target
std::copy(std::begin(source_data), std::end(source_data), std::begin(target_storage));
// Verify the transfer
for (int val : target_storage) {
std::cout << val << "\t";
}
return 0;
}
This operation relies on random access or forward iterators. You must preallocate the destination buffer to avoid undefined behavior caused by writing past bounds. If target_storage lacks sufficient capacity, the program may crash or corrupt memory. The type of stored objects must be copyable.
Conditional Tarnsfer
To filter data during the copy process, utilize std::copy_if. This variant evaluates a predicate for each element; only those returning true are moved to the output range.
#include <algorithm>
#include <vector>
#include <iostream>
bool exceeds_limit(int n) {
return n > 25;
}
int main() {
std::vector<int> raw_values = {10, 30, 20, 40};
std::vector<int> filtered_list;
// Push matching elements automatically
auto end_it = std::copy_if(std::begin(raw_values), std::end(raw_values),
std::back_inserter(filtered_list), exceeds_limit);
for (auto const& num : filtered_list) {
std::cout << num << " ";
}
return 0;
}
Here, exceeds_limit acts as the selection criterion. std::back_inserter ensures dynamic resizing, eliminating the need for manual size management before the call.
Fixed Count Copies
When processing streams or fixed-size segments, std::copy_n offers explicit control over the number of transferred items rather than relying on an end iterator for the source.
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<char> input_buf = {'a', 'b', 'c', 'd'};
std::vector<char> output_buf(2); // Allocate exact size needed
// Copy exactly 2 characters
std::copy_n(std::begin(input_buf), 2, std::begin(output_buf));
for (const char c : output_buf) {
std::cout << c;
}
return 0;
}
This is ideal when iterating through buffers where calculating the end iterator is inefficient or unnecessary. Capacity allocation remains the caller's responsibility.
Reverse Direction Transfers
std::copy_backward copies elements starting from the last item of the source down to the first. This is critical when dealing with overlapping ranges in-place, such as inserting into a vector without shifting existing elements manually.
#include <algorithm>
#include <vector>
#include <numeric>
#include <iostream>
int main() {
std::vector<int> src = {1, 2, 3};
std::vector<int> dst(3);
std::iota(std::begin(dst), std::end(dst), 100); // Fill dst with baseline
// Shift backwards to overwrite dst safely
std::copy_backward(std::begin(src), std::end(src), std::end(dst));
for (int i : dst) {
std::cout << i << " ";
}
return 0;
}
Unlike forward copy, the destination end iterator is passed as the third argument. Because it iterates backwards, it handles self-overlapping sequences correctly (e.g., moving data at the end of a buffer to the beginning of the same buffer) with out data corruption. Ensure the destination has space extending back from the given end iterator.