跳到主要内容

C++ 输出迭代器

什么是输出迭代器

输出迭代器是C++ STL迭代器层次结构中的基本类型之一,专门用于向容器或目的地写入数据。它是一种单向、单次遍历的迭代器,只支持向前移动且每个位置只能写入一次。

备注

输出迭代器是STL迭代器中要求最少的一类迭代器,主要关注写入操作而非读取操作。

输出迭代器的特性

输出迭代器具有以下主要特性:

  1. 写入功能:通过赋值操作将值写入指向的位置
  2. 前置和后置递增:可以通过++iteriter++向前移动
  3. 单向前进:只能向前移动,不能后退
  4. 单次遍历:每个位置只应写入一次
  5. 无比较操作:输出迭代器不支持比较操作(如==!=

输出迭代器的操作

输出迭代器支持的基本操作包括:

操作描述
*it = value向迭代器指向的位置写入值
++it前置递增,移至下一位置
it++后置递增,移至下一位置
it = it2赋值操作

标准库中的输出迭代器

C++标准库中提供了几种常见的输出迭代器:

1. std::ostream_iterator

这是一个用于向输出流写入数据的迭代器适配器。

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

int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};

// 创建一个输出流迭代器,向std::cout写入数据,每个元素后加空格
std::ostream_iterator<int> output_iter(std::cout, " ");

// 使用copy算法将vector中的元素复制到输出流
std::copy(nums.begin(), nums.end(), output_iter);

return 0;
}

输出:

1 2 3 4 5 

2. std::back_insert_iterator

用于在容器末尾插入元素的输出迭代器。

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

int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination;

// 创建一个back_insert_iterator
std::back_insert_iterator<std::vector<int>> back_it(destination);

// 复制元素到destination
std::copy(source.begin(), source.end(), back_it);

// 输出destination的内容
for(int num : destination) {
std::cout << num << " ";
}

return 0;
}

输出:

1 2 3 4 5 

3. std::front_insert_iterator

用于在容器前端插入元素的输出迭代器。

cpp
#include <iostream>
#include <deque>
#include <iterator>
#include <algorithm>

int main() {
std::deque<int> source = {1, 2, 3, 4, 5};
std::deque<int> destination;

// 创建一个front_insert_iterator
std::front_insert_iterator<std::deque<int>> front_it(destination);

// 复制元素到destination
std::copy(source.begin(), source.end(), front_it);

// 输出destination的内容
for(int num : destination) {
std::cout << num << " ";
}

return 0;
}

输出:

5 4 3 2 1 

4. std::insert_iterator

用于在容器指定位置插入元素的输出迭代器。

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

int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination = {10, 20, 30, 40, 50};

// 创建一个insert_iterator,插入点为destination的第三个元素位置
std::insert_iterator<std::vector<int>> insert_it(destination, destination.begin() + 2);

// 复制元素到destination
std::copy(source.begin(), source.end(), insert_it);

// 输出destination的内容
for(int num : destination) {
std::cout << num << " ";
}

return 0;
}

输出:

10 20 1 2 3 4 5 30 40 50 

便捷函数

STL提供了一些便捷函数来创建插入迭代器,而不需要明确指定迭代器类型:

  • std::back_inserter(container) - 创建back_insert_iterator
  • std::front_inserter(container) - 创建front_insert_iterator
  • std::inserter(container, iterator) - 创建insert_iterator
cpp
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination;

// 使用back_inserter便捷函数
std::copy(source.begin(), source.end(), std::back_inserter(destination));

// 输出destination的内容
for(int num : destination) {
std::cout << num << " ";
}

return 0;
}

输出:

1 2 3 4 5 

实际应用场景

文件处理

使用输出迭代器将数据写入文件:

cpp
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> data = {10, 20, 30, 40, 50};

// 打开文件用于写入
std::ofstream outFile("output.txt");

if (!outFile) {
std::cerr << "无法打开文件!" << std::endl;
return 1;
}

// 创建输出文件流迭代器
std::ostream_iterator<int> file_it(outFile, "\n");

// 将数据写入文件
std::copy(data.begin(), data.end(), file_it);

std::cout << "数据已成功写入文件" << std::endl;
return 0;
}

数据转换和过滤

使用输出迭代器结合算法进行数据转换:

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

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> even_numbers;

// 过滤出偶数并存入新容器
std::copy_if(numbers.begin(), numbers.end(),
std::back_inserter(even_numbers),
[](int n) { return n % 2 == 0; });

std::cout << "偶数: ";
for(int num : even_numbers) {
std::cout << num << " ";
}

std::vector<int> squared_numbers;

// 计算平方并存入新容器
std::transform(numbers.begin(), numbers.end(),
std::back_inserter(squared_numbers),
[](int n) { return n * n; });

std::cout << "\n平方数: ";
for(int num : squared_numbers) {
std::cout << num << " ";
}

return 0;
}

输出:

偶数: 2 4 6 8 10 
平方数: 1 4 9 16 25 36 49 64 81 100

合并数据流

使用输出迭代器合并多个数据源:

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

int main() {
std::vector<int> first_half = {1, 2, 3, 4, 5};
std::vector<int> second_half = {6, 7, 8, 9, 10};
std::vector<int> merged;

// 保留merged的容量以提高性能
merged.reserve(first_half.size() + second_half.size());

// 将第一个容器的内容复制到merged
std::copy(first_half.begin(), first_half.end(), std::back_inserter(merged));

// 将第二个容器的内容追加到merged
std::copy(second_half.begin(), second_half.end(), std::back_inserter(merged));

std::cout << "合并后的数据: ";
for(int num : merged) {
std::cout << num << " ";
}

return 0;
}

输出:

合并后的数据: 1 2 3 4 5 6 7 8 9 10 

自定义输出迭代器

我们可以创建自己的输出迭代器来满足特殊需求。以下是一个简单的示例,创建一个用于特殊格式化输出的迭代器:

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

// 自定义输出迭代器
class FormattedOutputIterator {
private:
std::ostream& out;
std::string prefix;
std::string suffix;
bool is_first;

public:
// 迭代器特性
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;

// 构造函数
FormattedOutputIterator(std::ostream& os, const std::string& pre, const std::string& suf)
: out(os), prefix(pre), suffix(suf), is_first(true) {}

// 赋值操作符
template<typename T>
FormattedOutputIterator& operator=(const T& value) {
if (is_first) {
is_first = false;
} else {
out << suffix;
}
out << prefix << value;
return *this;
}

// 解引用操作符(返回自身)
FormattedOutputIterator& operator*() { return *this; }

// 前置递增操作符
FormattedOutputIterator& operator++() { return *this; }

// 后置递增操作符
FormattedOutputIterator operator++(int) { return *this; }
};

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

// 使用自定义迭代器,每个数字前添加"Item: ",后加", "
FormattedOutputIterator formatter(std::cout, "Item: ", ", ");

std::copy(numbers.begin(), numbers.end(), formatter);

std::cout << "End of list";
return 0;
}

输出:

Item: 1, Item: 2, Item: 3, Item: 4, Item: 5End of list

总结

输出迭代器是C++ STL迭代器体系中的一类基础迭代器,专门用于写入操作。它们具有以下特点:

  1. 专注于写入操作而非读取操作
  2. 只能向前移动(不能倒退)
  3. 每个位置只能写入一次
  4. 不支持比较操作

标准库提供了多种常见的输出迭代器,包括:

  • std::ostream_iterator - 向输出流写入数据
  • std::back_insert_iterator - 在容器末尾插入元素
  • std::front_insert_iterator - 在容器前端插入元素
  • std::insert_iterator - 在容器指定位置插入元素

输出迭代器在文件处理、数据转换、数据过滤和合并等多种场景中有广泛应用。理解和熟练使用输出迭代器是掌握STL的重要一步。

练习

  1. 创建一个程序,使用std::ostream_iterator将一个vector中的所有元素以JSON数组格式输出(如[1,2,3,4,5])。

  2. 编写一个程序,从用户输入读取一系列整数,然后使用不同类型的插入迭代器将它们添加到不同的容器中。

  3. 使用std::transform和输出迭代器将一个字符串向量中的所有字符串转换为大写,并存储在新的向量中。

  4. 创建一个自定义输出迭代器,它将每个写入的数据项编号并格式化输出,例如"1. 苹果","2. 香蕉"等。

  5. 使用输出迭代器实现一个简单的CSV文件生成器,将多个数据容器的内容写入CSV格式文件。

额外资源

  • C++参考文档 - 迭代器库
  • Effective STL (Scott Meyers) - 包含关于迭代器高效使用的建议
  • C++ Primer (第5版) - 详细介绍了迭代器的概念和用法
提示

记住,虽然输出迭代器功能有限,但正是这种简化的接口使它们能够在各种不同的场景中灵活使用,特别是结合STL算法时。