A usual STL construct is:
vector<string> col;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(col));
where we use an istream_iterator to copy from std input (cin) to a vector.
Can anyone explain how this code works?
my problem is that I don't really understand this part:
istream_iterator<string>(cin), istream_iterator<string>()
First, note that in this case, there's no real need to use std::copy at all. You can just initialize the vector directly from the iterators:
vector<string> col((istream_iterator<string>(cin)),
istream_iterator<string>());
This probably doesn't make the code a whole lot easier to understand though.
As far as how the code works, it's probably a little more straighforward than you think. An istream_iterator looks vaguely like this:
template <class T>
class istream_iterator {
std::istream *is;
T data;
public:
istream_iterator(std::istream &is) : is(&is) { ++(*this); }
istream_iterator() : is(nullptr) {}
T operator++() { (*is) >> data; return *this; }
T operator++(int) { (*is) >> data; return *this; }
T const &operator*() { return data; }
bool operator !=(istream_iterator &end) { return (*is).good(); }
bool operator ==(istream_iterator &end) { return !(*is).good(); }
};
Obviously there's more more I'm skipping over, but that's most of what we care about here. So, what happens is that when you create the iterator, it reads (or attempts to) an item from the stream into the variable I've called data. When you dereference the iterator, it returns data. When you increment the iterator, it reads (or attempts to) the next item from the file. Despite being written as if they compare one iterator to another, operator== and operator!= really just check for the end of the file1.
That's then used by std::copy, which (again simplified) looks vaguely like this:
template <class InIt, class OutIt>
void std::copy(InIt b, InIt e, OutIt d) {
while (b != e) {
*d = *b;
++b;
++d;
}
}
So, this reads and item from the input iterator, writes that item to the output iterator, and repeats until the iterator for the current position compares equal to the iterator for the end of the input (which will happen when you reach the end of the file). Note that unlike other iterators, the only "end" position you're allowed to use with an istream iterator is the end of the file.
Note that technically, this isn't conforming behavior. I've simplified comparison to keep things simple. Two default-constructed iterators should compare equal, and if you construct two iterators from the same stream, they should compare equal at least before you've read anything from the stream. This makes little practical difference though -- the only comparison you seen in real use is to determine whether you've reached the end of file yet.
Part of the answer below is quoted from C++ standard library: A tutorial and reference by Nicolai M. Josuttis with a little tweaks.
The expression
istream_iterator<string>(cin)
creates a string iterator that reads from the standard input stream cin. The template argument string specifies that the stream iterator reads elements of this type. These elements are read with the usual input operator >>. Thus, each time the algorithm wants to process the next element, the istream iterator transforms that desire into a call of
cin >> string
The input operator for strings usually reads one word separated by whitespaces.
The expression
istream_iterator<string>()
calls the default constructor of the istream iterators that creates a so-called end-of-stream iterator. It represents a stream from which you can no longer read. The end-of-string iterator is used as the end of the range, so the algorithm copy reads all strings from cin until it can no longer read any more.
The last one:
back_inserter(col))
according to back_inserter documentation:
A std::back_insert_iterator which can be used to add elements to the end of the container c
It will add all read in strings into col.
You can find information about std::istream_iterator and std::back_inserter for details.
Related
Is there is any similar solution to this command:
using namespace std;
copy(istream_iterator<string>(cin), istream_iterator<string>(),ostream_iterator<string>(cout, "\n"));
-- this command copies everything into cout but I would like to change it to copy the string in reverse order so I have used this:
using namespace std;
reverse_copy(istream_iterator<string>(cin), istream_iterator<string>(),ostream_iterator<string>(cout, "\n"));
-- but this did not even compile. Are there any solutions to this? Thank you
The first two arguments to std::reverse_copy must be Bidirectional Iterator whereas std::istream_iterator is Input Iterator which cannot behave as Bidirectional Iterator. That explains why it doesn't work — it wouldn't even compile.
You've to write your own iterator — or do it manually in a loop — to solve this problem (which is not clear as to what mean by reverse : given foo bar as input, do you want bar foo or oof rab, or rab oof? as many of the commenters say).
You can write a recursive function. For example
#include <iostream>
#include <string>
#include <sstream>
std::ostream & reverse_output( std::istream &is = std::cin,
std::ostream &os = std::cout )
{
std::string s;
if ( is >> s ) reverse_output( is, os ) << s << '\n';
return os;
}
int main()
{
std::istringstream is( "Hello Bobul Mentol" );
reverse_output( is );
}
The program output is
Mentol
Bobul
Hello
Of course instead of the string stream I used for the demonstrative purpose you can use std::cin. In this case the call of the function will look just like
reverse_output();
Otherwise you need to store the input in some container and use it to reverse the inputted data for outputing.
For example
std::vector<std::string> v( std::istream_iterator<std::string>( std::cin ),
std::istream_iterator<std::string>() );
std::reverse_copy( v.begin(), v.end(),
std::ostream_iterator<std::string>( std::cout, "\n" ) );
I have never heard of some standard algorithm which can copy a reversed collection by an input_iterator or even forward_iterator - probably if this exist, it requires at least bidirectional_iterator.
So, you can use the temporary collection to store the values read, like this:
vector<string> tmp;
copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(tmp));
copy(tmp.rbegin(), tmp.rend(), ostream_iterator<string>(cout, "\n"));
There is a general problem here: std::cin is a stream. When it is attached to a file, you could imagine a way to initially find the size and so how to know where the reverse iterator should start. But when it is attached to a terminal, with an imprevisible human being able to type input data at will, at what position should the reverse iterator start? I have no idea of it, and it looks like cin designer had no more - more seriously, cin does not propose a reverse iterator, and it is by design.
If you want to present what has been inputted in cin but in reverse order, you must first specify:
what is the piece of input to reverse: anything until stream is closed, or anything until first end of line, or [put here your own definition]. Once it's done you have the start place for your reverse iterator
what is the unit to be reversed: one character or one word at a time. Once this is done, you know what your reverse iterator should return.
The implementation could use a vector of strings. You consistently accumulate words or single characters in it until what you have defined as the end of the stream. Once you hit the end, you hold a container with bidirectional iterators so copying it in reverse order should be easy.
I have a weird behavior, and this is probably a beginner's question:
In a class member function I am trying to replace a given vector by another vector.
template <typename FITNESS_TYPE>
void BaseManager<FITNESS_TYPE>::replacePopulation (
typename Population<FITNESS_TYPE>::chromosome_container replacementPopulation)
{
_population.getChromosomes().clear();
//This inserts the contents of replacementPopulation into _population.getChromosomes()
for (
typename Population<FITNESS_TYPE>::chromosome_container::iterator
it = replacementPopulation.begin();
it != replacementPopulation.end();
++it)
{
_population.getChromosomes().push_back(*it);
}
//But this does nothing...
std::copy(replacementPopulation.begin(),replacementPopulation.end(), _population.getChromosomes().begin());
for (typename Population<FITNESS_TYPE>::chromosome_container::iterator it = _population.getChromosomes().begin(); it!=_population.getChromosomes().end(); ++it)
{
std::cout << "CHROM: " << **it << std::endl;
}
}
The corresponding getChromosomes() getter are as follows:
template <typename FITNESS_TYPE>
class Population : public printable {
public:
typedef typename std::vector<Chromosome::BaseChromosome<FITNESS_TYPE>* > chromosome_container;
typedef typename chromosome_container::const_iterator const_it;
typedef typename chromosome_container::iterator it;
const chromosome_container& getChromosomes() const { return _chromosomes; }
chromosome_container& getChromosomes() { return _chromosomes; }
private:
chromosome_container _chromosomes;
};
Im confused. Why does the copy not work like the for loop?
push_back resizes the vector, whereas writing to begin() and what comes after it assumes that the space is already there. What you want looks like this:
std::copy(replacementPopulation.begin(),
replacementPopulation.end (),
std::back_inserter(_population.getChromosomes()));
#include <iterator> to get back_inserter.
In essence, std::back_inserter is an iterator that does a push_back every time something is written to it.
copy requires that its output iterator be the start of a valid range at least as large as the input range. In your case, it's the start of an empty range; so copy will increment it off the end of the vector, writing into whatever memory lies beyond, and causing undefined behaviour.
The simplest solution here is just to reassign the vector
_population.getChromosomes() = replacementPopulation;
If you did need to append to a vector, rather than replace all its contents, you could use an insertion iterator:
std::copy(replacementPopulation.begin(), replacementPopulation.end(),
std::back_inserter(_population.getChromosomes()));
vector actually has an insert method that takes iterators:
_population.getChromosomes().insert(
_population.getChromosomes().end(),
replacementPopulation.begin(),
replacementPopulation.end());
That'll make sure that _population.getChromosomes() is resized correctly so you can't run off the end. Also will only do one reserve() if necessary based on the distance between the two iterators, so this will be strictly more efficient than the std::copy() solutions proposed.
Alternatively, if you're literally just copying the vector:
_population.getChromosomes() = replacementPopulation;
Copy assumes that there is space for copied elements in destination container, and it will replace them. You can use "back_inserter" to create an special iterator that will insert elements instead of replacing to avoid the need for resizing before the copy.
std::copy(replacementPopulation.begin(),replacementPopulation.end(), std::back_inserter(_population.getChromosomes()));
Herb presents a way to loop through the vector:
for(vector<int>::iterator i = v.begin(); i < v.end(); i++) {
cout << *i << endl;
}
He replaces this code with:
copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));
I am struggling to understand how, or why, this works. I looked up the copy function and the documentation says that it is equivalent to:
template<class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last,
OutputIterator result)
{
while (first!=last) {
*result = *first;
++result; ++first;
}
return result;
}
So I developed the question, "What happens when we * OutputIterator?"
reference operator*() const;
Dereference iterator
Returns *this.
And that is where I got confused. I do not see a definition of what OutputIterator is pointing to. Additionally, I do not see how the line *result = *first; could possibly translate to invoking cout << *i;
You only looked up what an OutputIterator does. OutputIterator is just a set of requirements that a bunch of types in the standard library meet. One of those types is the std::ostream_iterator, so you need to look at how this behaves in the context of std::copy.
So in the copy algorithm, we're doing *result = *first. Firstly, the operator* for std::ostream_iterator does nothing - it just returns the iterator itself. The magic happens when we assign to this iterator. If you look up std::ostream_iterator::operator=, you'll see that assigning to this iterator will insert (using <<) into the stream it was constructed with. So the assignment in your case will stream into std::cout.
After this, both result and first are incremented. Incrementing result (the std::ostream_iterator) has no effect, and incrementing first will move to the next element in the vector. Then in the next iteration, this next element is inserted into std::cout again, and so on.
As you can see, std::ostream_iterator doesn't really behave in the way that you would expect a typical iterator to behave (moving through a sequence of elements where performing indirection on them gives you the current element). However, it does meet the requirements of an OutputIterator and so can be used as one.
Here's the implementation of std::ostream_iterator::operator= from libstdc++:
/// Writes #a value to underlying ostream using operator<<. If
/// constructed with delimiter string, writes delimiter to ostream.
ostream_iterator&
operator=(const _Tp& __value)
{
__glibcxx_requires_cond(_M_stream != 0,
_M_message(__gnu_debug::__msg_output_ostream)
._M_iterator(*this));
*_M_stream << __value;
if (_M_string) *_M_stream << _M_string;
return *this;
}
Ignoring the assertion on the first line, we can see that it then inserts __value into its internal _M_stream stream. Then, if there is a delimiter set, _M_string, it also gets inserted into _M_stream. Then it returns.
I'm confused as to whether I should increment an OutputIterator when I set it. See the following code in which I'm trying to split a string. My problem is with the third line of the while loop, the code seems to work fine whether I have *oit = ... or *oit++ = ...
Can someone explain to me why?
template<class O> void split(string& s, O oit){
string::iterator jt, it = s.begin();
while(1){
jt = find(it, s.end(), ' ');
if(it == s.end() && jt == s.end()) return;
*oit++ = string(it, jt);
it = jt;
if(it != s.end() ) it++;
}
}
...
int main(){
string s;
getline(cin, s);
vector<string> v;
split(s, back_inserter(v));
copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));
}
std::back_inserter creates an iterator that inserts by calling push_back on the underlying collection. That means the increment isn't necessary for it to work correctly.
The same is not necessarily true of other output iterators though, so for your code to be correct, it should perform the increment, event though in this particular case it's basically ignored.
Just for what it's worth, in this particular case you can get the same basic effect with a lot less/simpler code:
string s;
getline(cin, s);
replace(s, ' ', '\n');
cout << s;
The concept requires that you increment an output iterator for each write you do. Although the std::back_insert_iterator<T> may call push_back() on the corresponding object on each assignment to *it, the concept still demands that the increment operator is called. In principle, output iterators could be function calls but to fit into the same interface used also by pointers, they need to support the same operations.
The specification of std::back_insert_iterator<Cont> states that each assignment of a typename Cont::value_type calls cont.push_back(value) on the underlying type, operator*() just returns the iterator itself, as does operator++().
Both parts work because standard iterators are designed to be functionally equivalent to raw pointers when used with generic programming. When raw pointers are used, they must be incremented to reach the subsequent address.
I have a txt file containing a bunch of words, one per line.
I need to read this file and put each word in a list
then the user will be able to modify this list
when done editing, the program will write the modified list in a new file.
Since it's object orinted c++, I'm gonna have two classes, one to read/write to file, and one to edit/mess with the list and the user.
with this approach in mind, here's my read function from the first class:
bool FileMgr::readToList(list<string> &l)
{
if(!input.is_open())
return false;
string line;
while(!input.eof())
{
getline(input, line);
l.push_back(line);
}
return true;
}
keep in mind: input is opened at constructor.
questions: is there a less redundant way of getting that damn line from istream and pushing it back to l? (without the 'string' in between).
questions aside, this functions seems to work properly.
now the output function:
bool FileMgr::writeFromList(list<string>::iterator begin, list<string>::iterator end)
{
ofstream output;
output.open("output.txt");
while(begin != end)
{
output << *begin << "\n";
begin++;
}
output.close();
return true;
}
this is a portion of my main:
FileMgr file;
list<string> words;
file.readToList(words);
cout << words.front() << words.back();
list<string>::iterator begin = words.begin();
list<string>::iterator end = words.end();
file.writeFromList(begin, end);
thanks for the help, both functions now work.
Now regarding style, is this a good way to implement these two functions?
also the getline(input,line) part I really don't like, anyone got a better idea?
As written, your input loop is incorrect. The eof flag is set after a read operation that reaches eof, so you could end up going through the loop one too many times. In addition, you fail to check the bad and fail flags. For more information on the flags, what they mean, and how to properly write an input loop, see the Stack Overflow C++ FAQ question Semantics of flags on basic_ios.
Your loop in readToList should look like this:
std::string line;
while (std::getline(input, line))
{
l.push_back(line);
}
For a more C++ way to do this, see Jerry Coffin's answer to How do I iterate over cin line-by-line in C++? His first solution is quite straightforward and should give you a good idea of how this sort of thing looks in idiomatic, STL-style C++.
For your writeFromList function, as Tomalak explains, you need to take two iterators. When using iterators in C++, you almost always have to use them in pairs: one pointing to the beginning of the range and one pointing to the end of the range. It is often preferable as well to use a template parameter for the iterator type so that you can pass different types of iterators to the function; this allows you to swap in different containers as needed.
You don't need to explicitly call output.close(): it is called automatically by the std::ofstream destructor.
You can use std::copy with std::ostream_iterator to turn the output loop into a single line:
template <typename ForwardIterator>
bool FileMgr::writeFromList(ForwardIterator first, ForwardIterator last)
{
std::ofstream output("output.txt");
std::copy(first, last, std::ostream_iterator<std::string>(output, ""));
}
writeFromList should take a start iterator and an end iterator. This range-based approach is what the iterators are designed for, and it's how the stdlib uses them.
So:
bool FileMgr::writeFromList(list<string>::iterator it, list<string>::iterator end)
{
ofstream output("output.txt");
for (; it != end; ++it)
output << *it;
return true;
}
and
file.writeFromList(words.begin(), words.end());
You'll notice I improved your stream usage a little, too.
Ideally writeFromList would be generic and take any iterator type. But that's future work.
Also note that your .eof is wrong. Do this:
string line;
while (getline(input, line))
l.push_back(line);