📜 ⬆️ ⬇️

Complicating the standard example

The standard C ++ library offers not only a set of classes, but also determines the way programs are written. This article discusses the general requirements for implementing programs using STL.

Consider the following task:
Read from the file input.txt array of integers separated by whitespace. Sort them and write to the file output.txt

You can write the following solution:

#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; } 

A few words about the "magic" in the code:
')

This example is actually quite simple. However, he can help us with the following task:
A file containing information about people is stored in the file input.txt: last name, first name, age (each line is a record, the data is separated by a space). Read this data into an array, sort it by age and write to the file output.txt. Display information about a person whose age is more than 20, but less than 25 years old.
In principle, the decision will be almost the same. However, to save the decision, it is necessary to carry out the preparatory work, namely:

  1. Declare the data structure. - it is possible to define something serviceable, but in the specific case a struct is enough:

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

    I strongly recommend thinking about the implementation of copy constructors, with parameters and defaults, as well as the copy operator. With the further development of the project you will definitely need them.
  2. Overload I / O statements — these operators are manipulated by iterators over threads. And in general, they are accustomed to use.

     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. Determine the rules for ordering objects - There is already a large expanse: you can redefine the operator <, you can describe a function, a functor or a lambda expression. In this case, we use the function.

     bool comparator(const man& p1, const man& p2){ return p1.age < p2.age; } 
  4. Define the rule of selection of objects - Again, a fairly large selection of implementation. This time, let there be a functor (an object of the class in which the operator parentheses [the functor ] is defined) to which you can pass the age span:

     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); } }; 

    Pay attention to the constructor of the functor - so we can customize its behavior.

Well, actually, the entry point into the program:

 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; } 

As you can see, the changes to the main function are minimal, only affect the type of vector elements. Plus added a call to the copy_if algorithm. This useful algorithm appeared with the standard C ++ 11, it copies the elements from one container to another only those elements that satisfy the condition.

What conclusions can be drawn from this?

  1. Knowledge and active use of standard library algorithms significantly speeds up development (more precisely, brings it to automatism).
  2. It is useful to declare various constructors and copy operators for data structures. They are used in various situations, in particular, when inserting items into containers.
  3. For convenience, you can overload the input and output operators, as well as the comparison operator and the ordering operator.
  4. Functors - a powerful tool that allows you to implement functions with "memory" or additional behavior
  5. ... maybe some other ...

Thank you for your time!

All program code:

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; } 

Bibliography:

  1. Stepanov Al. Lee Meng, The Standard Template Library, 1995
  2. CPP Reference, copy
  3. CPP Reference, inserter
  4. CPP Reference, istream_iterator
  5. CPP Reference, ostream_iterator
  6. Wiki functor

Source: https://habr.com/ru/post/433218/


All Articles