复杂的标准示例

C ++标准库不仅提供了一组类,而且还确定了程序的编写方式。 本文讨论了使用STL实施程序的一般要求。

请考虑以下任务:
从input.txt文件中读取一个由空格分隔的整数数组。 对它们进行排序并写入output.txt

您可以编写以下解决方案:

#include <vector> #include <algorithm> #include <fstream> int main(){ //  input.txt   std::ifstream fin("input.txt"); //  output.txt   std::ofstream fout("output.txt"); //       std::vector<int> v; //  ,           std::copy(std::istream_iterator<int>(fin), std::istream_iterator<int>(), std::inserter(v, v.end())); //   std::sort(v.begin(), v.end()); //  ,          std::copy(v.begin(), v.end(), std::ostream_iterator<int>(fout, " ")); return 0; } 

关于代码中“魔术”的几句话:

  • 库的基础之一是迭代器,以及它们定义的半间隔。 根据语义(按行为读取),它们与指针重合。 也就是说,解引用运算符*将为您返回迭代器所引用的元素,++会将迭代器转换为下一个元素。 特别是,任何容器都由其结束迭代器[begin,end)表示,其中begin指向第一个元素,end- 最后一个
  • 使用容器的算法,将参数作为容器(或其一部分)的开始和结束。
  • 复制复制算法只是将元素从一个半间隔重写为另一个半间隔。 如果没有在目标容器中分配内存,则该行为是不可预测的。
  • inserter函数在指定的迭代器[ inserter ]之前将值插入到容器中
  • istream_iterator和ostream_iterator提供对流的容器式访问[ istream_iteratorostream_iterator ]

这个例子实际上很简单。 但是,他可以帮助我们解决以下问题:
input.txt文件包含一个列表,其中包含有关人员的信息:姓氏,名字,年龄(每行是一条记录,数据用空格分隔)。 将此数据读入数组,按年龄排序,然后写入output.txt文件。 显示有关年龄大于20但小于25岁的人的信息。
原则上,解决方案将几乎相同。 但是,为了保存该决定,有必要进行准备工作,即:

  1. 声明一个数据结构。 -您可以定义一些有用的东西,但是在特定情况下,struct就足够了:

     struct man{ std::string firstname, secondname; size_t age; }; 

    我强烈建议您考虑使用默认参数和复制运算符来实现复制构造函数。 随着项目的进一步发展,您一定会需要它们。
  2. 重载I / O运算符-这些运算符由线程上的迭代器操纵。 无论如何,更常见的是使用它们。

     std::ostream& operator << (std::ostream& out, const man& p){ out << p.firstname << " " << p.secondname << " " << p.age; return out; } std::istream& operator >> (std::istream& in, man& p){ in >> p.firstname >> p.secondname >> p.age; return in; } 
  3. 定义对象排序规则 -这已经是一个很大的领域:您可以覆盖运算符<,可以描述函数,函子或lambda表达式。 在这种情况下,请使用该功能。

     bool comparator(const man& p1, const man& p2){ return p1.age < p2.age; } 
  4. 定义选择对象的规则 -再次选择相当多的实现。 这次,让一个可以传递年龄范围的子(定义了括号 [ functor ]运算符的类的一个对象):

     struct predicate{ size_t begin, end; predicate(int p1, int p2): begin(p1), end(p2) {} bool operator ()(const man& p){ return (p.age > begin) && (p.age < end); } }; 

    注意函子的构造函数-这样我们可以自定义其行为。

好吧,实际上,该程序的入口点是:

 int main(){ std::ifstream fin("input.txt"); std::ofstream fout("output.txt"); std::vector<man> v; std::copy(std::istream_iterator<man>(fin), std::istream_iterator<man>(), std::inserter(v, v.end())); std::sort(v.begin(), v.end(), comparator); std::copy_if(v.begin(), v.end(), std::ostream_iterator<man>(std::cout, "\n"), predicate(20, 25)); std::copy(v.begin(), v.end(), std::ostream_iterator<man>(fout, "\n")); return 0; } 

如您所见,对main函数的更改很小,仅影响矢量元素的类型。 加号添加了对copy_if算法的调用。 这种有用的算法随C ++ 11标准一起出现;它将元素从一个容器复制到仅满足条件的那些元素。

由此可以得出什么结论?

  1. 知道并积极使用标准库的算法可以极大地加快开发速度(更准确地说,它会导致自动化)。
  2. 为数据结构声明各种构造函数和复制运算符很有用。 它们用于各种情况,尤其是在将元素插入容器中时。
  3. 为了方便起见,您可以重载输入和输出运算符以及比较运算符和排序运算符。
  4. Functors-一个功能强大的工具,可让您使用“内存”或其他行为来实现功能
  5. ...也许更多...

谢谢你的耐心!

所有程序代码:

an_example.cpp
 #include <string> #include <vector> #include <fstream> #include <algorithm> #include <iostream> #include <iterator> struct man{ std::string firstname, secondname; size_t age; }; std::ostream& operator << (std::ostream& out, const man& p){ out << p.firstname << " " << p.secondname << " " << p.age; return out; } std::istream& operator >> (std::istream& in, man& p){ in >> p.firstname >> p.secondname >> p.age; return in; } bool comparator(const man& p1, const man& p2){ return p1.age < p2.age; } struct predicate{ size_t begin, end; predicate(int p1, int p2): begin(p1), end(p2) {} bool operator ()(const man& p){ return (p.age > begin) && (p.age < end); } }; int main(){ std::ifstream fin("input.txt"); std::ofstream fout("output.txt"); std::vector<man> v; std::vector<man>::iterator i; std::copy(std::istream_iterator<man>(fin), std::istream_iterator<man>(), std::inserter(v, v.end())); std::sort(v.begin(), v.end(), comparator); std::copy_if(v.begin(), v.end(), std::ostream_iterator<man>(std::cout, "\n"), predicate(20, 25)); std::copy(v.begin(), v.end(), std::ostream_iterator<man>(fout, "\n")); return 0; } 

参考书目:

  1. Stepanov Al。 李萌,标准模板库,1995年
  2. CPP参考,副本
  3. CPP参考,插入器
  4. CPP参考,istream_iterator
  5. CPP参考,ostream_iterator
  6. 维基函子

Source: https://habr.com/ru/post/zh-CN433218/


All Articles