How do I iterate over cin line by line in C++? - c++

I want to iterate over std::cin, line by line, addressing each line as a std::string. Which is better:
string line;
while (getline(cin, line))
{
// process line
}
or
for (string line; getline(cin, line); )
{
// process line
}
? What is the normal way to do this?

Since UncleBen brought up his LineInputIterator, I thought I'd add a couple more alternative methods. First up, a really simple class that acts as a string proxy:
class line {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, line &l) {
std::getline(is, l.data);
return is;
}
operator std::string() const { return data; }
};
With this, you'd still read using a normal istream_iterator. For example, to read all the lines in a file into a vector of strings, you could use something like:
std::vector<std::string> lines;
std::copy(std::istream_iterator<line>(std::cin),
std::istream_iterator<line>(),
std::back_inserter(lines));
The crucial point is that when you're reading something, you specify a line -- but otherwise, you just have strings.
Another possibility uses a part of the standard library most people barely even know exists, not to mention being of much real use. When you read a string using operator>>, the stream returns a string of characters up to whatever that stream's locale says is a white space character. Especially if you're doing a lot of work that's all line-oriented, it can be convenient to create a locale with a ctype facet that only classifies new-line as white-space:
struct line_reader: std::ctype<char> {
line_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
To use this, you imbue the stream you're going to read from with a locale using that facet, then just read strings normally, and operator>> for a string always reads a whole line. For example, if we wanted to read in lines, and write out unique lines in sorted order, we could use code like this:
int main() {
std::set<std::string> lines;
// Tell the stream to use our facet, so only '\n' is treated as a space.
std::cin.imbue(std::locale(std::locale(), new line_reader()));
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::inserter(lines, lines.end()));
std::copy(lines.begin(), lines.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Keep in mind that this affects all input from the stream. Using this pretty much rules out mixing line-oriented input with other input (e.g. reading a number from the stream using stream>>my_integer would normally fail).

What I have (written as an exercise, but perhaps turns out useful one day), is LineInputIterator:
#ifndef UB_LINEINPUT_ITERATOR_H
#define UB_LINEINPUT_ITERATOR_H
#include <iterator>
#include <istream>
#include <string>
#include <cassert>
namespace ub {
template <class StringT = std::string>
class LineInputIterator :
public std::iterator<std::input_iterator_tag, StringT, std::ptrdiff_t, const StringT*, const StringT&>
{
public:
typedef typename StringT::value_type char_type;
typedef typename StringT::traits_type traits_type;
typedef std::basic_istream<char_type, traits_type> istream_type;
LineInputIterator(): is(0) {}
LineInputIterator(istream_type& is): is(&is) {}
const StringT& operator*() const { return value; }
const StringT* operator->() const { return &value; }
LineInputIterator<StringT>& operator++()
{
assert(is != NULL);
if (is && !getline(*is, value)) {
is = NULL;
}
return *this;
}
LineInputIterator<StringT> operator++(int)
{
LineInputIterator<StringT> prev(*this);
++*this;
return prev;
}
bool operator!=(const LineInputIterator<StringT>& other) const
{
return is != other.is;
}
bool operator==(const LineInputIterator<StringT>& other) const
{
return !(*this != other);
}
private:
istream_type* is;
StringT value;
};
} // end ub
#endif
So your loop could be replaced with an algorithm (another recommended practice in C++):
for_each(LineInputIterator<>(cin), LineInputIterator<>(), do_stuff);
Perhaps a common task is to store every line in a container:
vector<string> lines((LineInputIterator<>(stream)), LineInputIterator<>());

The first one.
Both do the same, but the first one is much more readable, plus you get to keep the string variable after the loop is done (in the 2nd option, its enclosed in the for loop scope)

Go with the while statement.
See Chapter 16.2 (specifically pages 374 and 375) of Code Complete 2 by Steve McConell.
To quote:
Don't use a for loop when a while loop is more appropriate. A common abuse of the flexible for loop structure in C++, C# and Java is haphazardly cramming the contents of a while loop into a for loop header.
.
C++ Example of a while loop abusively Crammed into a for Loop Header
for (inputFile.MoveToStart(), recordCount = 0; !inputFile.EndOfFile(); recordCount++) {
inputFile.GetRecord();
}
C++ Example of appropriate use of a while loop
inputFile.MoveToStart();
recordCount = 0;
while (!InputFile.EndOfFile()) {
inputFile.getRecord();
recordCount++;
}
I've omitted some parts in the middle but hopefully that gives you a good idea.

This is based on Jerry Coffin's answer. I wanted to show c++20's std::ranges::istream_view. I also added a line number to the class. I did this on godbolt, so I could see what happened. This version of the line class still works with std::input_iterator.
https://en.cppreference.com/w/cpp/ranges/basic_istream_view
https://www.godbolt.org/z/94Khjz
class line {
std::string data{};
std::intmax_t line_number{-1};
public:
friend std::istream &operator>>(std::istream &is, line &l) {
std::getline(is, l.data);
++l.line_number;
return is;
}
explicit operator std::string() const { return data; }
explicit operator std::string_view() const noexcept { return data; }
constexpr explicit operator std::intmax_t() const noexcept { return line_number; }
};
int main()
{
std::string l("a\nb\nc\nd\ne\nf\ng");
std::stringstream ss(l);
for(const auto & x : std::ranges::istream_view<line>(ss))
{
std::cout << std::intmax_t(x) << " " << std::string_view(x) << std::endl;
}
}
prints out:
0 a
1 b
2 c
3 d
4 e
5 f
6 g

Related

How to assign the contents of multiple files to different classes attributes through just one loop?

I have three different text files called a.txt, b.txt and c.txt to be taken from the command line. I have also three classes called class A, class B and class C each of which corresponds to each of those files. For instance, "a.txt" contains:
12 title1
15 title2
20 title3
where the first column is the "id" and the second one is the title(in each row there is a space between the id and the title). Corresponds to this file is Class A which its header file is like:
class A {
public:
A();
// the id doesn't need to be int
A(const string &id, const string &title);
void setId(const string &id);
void setTitle(const string &title);
private:
string id_;
string title_;
};
The program should take the arguments (which are the files) from command line, read the contents of each file and extracts its content to assign the variables of the corresponding class. Following the above example, the program through setID should assign "12" to a1.id_ and through setTitle assign "title1" to a1.title_ and the same for the other two instances. Is it possible to do the all mentioned jobs with all of files and the classes through just one efficient loop? In either case (if possible or not possible) what is the suggested solution?
Edit
Creating so many differently-named variables for each class is not cost effective at all
We will store all the data in a container. And for this task, we need a dynamic container, which can grow. A std::vector is the way to go.
To make this code efficient, we will overwrite the inserter and extractor operator of your class A. The inserter will simply insert the ID and the Title into the output stream. Easy to understand.
The extractor is slightly more complicated, but also easy to understand. We first extract the id, with a standard ">>" operation. Then we read the rest of the line with std::getline because the title may contain blanks. That would be a delimiter for the ">>" operator. Please note, the std::getline will read leading/trailing blanks. Maybe you need to "trim" your Title-string.
In main, we simply loop through the command line arguments and open the file for each argument. If it could be opened, the we use std::copy to copy all lines of the file, so the complete content, into our std::vector of type A.
The std::istream_terator will call the overwritten extractor operator of our A-class, line for line, until the file is at the end. The std::back_inserter will "push_back" the read A instances into the vector.
At the end of main, we show the complete content of the A-vector.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <iterator>
#include <algorithm>
class A {
public:
// Constructors
A() : id_(), title_() {}
A(const std::string& id, const std::string& title) : id_(id), title_(title) {}
// Setters
void setId(const std::string& id) { id_ = id; }
void setTitle(const std::string& title) { title_ = title; }
// Overwrite extractor for easier reading
friend std::istream& operator >> (std::istream& is, A& a) {
if (std::string id{}, title{}; is >> id && getline(is, title)) {
a.id_ = id; a.title_ = title;
}
return is;
}
// Overwrite inserter for easier writing
friend std::ostream& operator << (std::ostream& os, const A& a) {
return os << "Id: " << std::setw(5) << a.id_ << " Title: " << a.title_ << "\n";
}
private:
std::string id_{};
std::string title_{};
};
int main(int argc, char* argv[]) {
// Here we will store all read data
std::vector<A> data{};
// Work on all command line arguments
for (size_t fileNumber = 1; fileNumber < argc; ++fileNumber) {
// Open the corresponding file and check, if it is open
if (std::ifstream ifs(argv[fileNumber]); ifs) {
// Copy all data from this file into the class and the vector
std::copy(std::istream_iterator<A>(ifs), {}, std::back_inserter(data));
}
}
// Show the result on the screen
std::copy(data.begin(), data.end(), std::ostream_iterator<A>(std::cout));
return 0;
}

Overloading cout for logging purposes?

I would like to define something like a new cout, which I can use to log my data:
some_type cout2( Message_type message ){
cout << message;
logfile.save(message);
}
so I will use it with
cout2 << "some message" << endl;
Up to now I was not able to find out how the code above has to look like exactly.
Thanks for your help.
You can create your own logger like:
class Logger {
public:
Logger(std::string const& filename)
: stream_(filename, std::ofstream::out | std::ofstream::app)
{
if (!stream_) {
// Error...
}
}
Logger& operator<<(std::string const& str) {
std::cout << str;
stream_ << str;
return *this;
}
private:
std::ofstream stream_;
};
Generally speaking, classes from C++ standard library are not designed to be derived, and that is true for stream classes.
So IMHO, it is better to specify what method you will need on your cout2 object, and then:
design a class containing a ostream& object, initialized in ctor
delegate actual output to that internal object
do whatever log you need in your methods
You should use templated a operator << to be able to easily process any class that std::ostream can process.
class LogStream {
std::ostream& out;
Logfile logfile;
LogStream(std::ostream& out, /* param for logfile initialization */ ...)
: out(out), logfile(...) {}
... // other useful methods for state
};
template<typename T>
LogStream& operator << (LogStream& out, T val) {
out.out << message;
// should first test whether T is manipulator, and choose whether and how it should be logged
logfile.save(message);
}
You don't want to modify std::cout.
Instead, you want to create a specialised std::streambuf that writes to two buffers rather than one. For example;
#include <streambuf>
template <typename char_type,
typename traits = std::char_traits<char_type> >
class basic_teebuf:
public std::basic_streambuf<char_type, traits>
{
public:
typedef typename traits::int_type int_type;
basic_teebuf(std::basic_streambuf<char_type, traits> * sb1,
std::basic_streambuf<char_type, traits> * sb2)
: sb1(sb1)
, sb2(sb2)
{
}
protected: // override virtuals inherited from std::basic_streambuf
virtual int sync()
{
int const r1 = sb1->pubsync();
int const r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}
virtual int_type overflow(int_type c)
{
int_type const eof = traits::eof();
if (traits::eq_int_type(c, eof))
{
return traits::not_eof(c);
}
else
{
char_type const ch = traits::to_char_type(c);
int_type const r1 = sb1->sputc(ch);
int_type const r2 = sb2->sputc(ch);
return
traits::eq_int_type(r1, eof) ||
traits::eq_int_type(r2, eof) ? eof : c;
}
}
private:
std::basic_streambuf<char_type, traits> * sb1;
std::basic_streambuf<char_type, traits> * sb2;
};
typedef basic_teebuf<char> teebuf;
Then you need to create a specialised ostream which uses such a buffer
#include <ostream>
class teestream : public std::ostream
{
public:
// Construct an ostream which tees output to the supplied
// ostreams.
teestream(std::ostream & o1, std::ostream & o2);
private:
teebuf tbuf;
};
teestream::teestream(std::ostream & o1, std::ostream & o2)
: std::ostream(&tbuf)
, tbuf(o1.rdbuf(), o2.rdbuf())
{
}
All the above does is create a specialised std::ostream that uses our specialised buffer, which in turn makes use of two buffers.
Now, our teestream needs to be initialised using two streams. For example
#include <fstream>
#include <iostream>
// include the preceding definition of teestream here
int main()
{
std::ofstream logfile("hello-world.log");
teestream tee(std::cout, logfile);
// tee is now a stream that writes the same output to std::cout and logfile
tee << "Hello, world!\n";
return 0;
}
The advantage of this is that all stream insertions (operator <<) will work with our teestream - even for classes with overloaded versions.
When main() returns, the streams will also be closed cleanly.
I've written the specalised streambuf as a template (std::streambuf is a specialisation of a templated class named std::basic_streambuf). For generality, it would probably be better to do the same with the stream (using the fact that std::ostream is also a specialisation of a templated std::basic_ostream). I leave that sort of generalisation as an exercise.
The logging systems I've seen, built on this idea look something like this:
#define MY_PRINT(x, ...) \
{ \
fprintf(logFile, x, ##__VA_ARGS__); \
fflush(acuLogFile); \
}
And you would use it like:
MY_PRINT("this is just a test\n");
Even though this is the C way of doing things, it is very versatile and work in C++ as well.
You just have to use your newly define print function everywhere in the code.
Maybe you should have an instance based logger with a .log() method, that, depending on implementation can log to file, write to stdout etc, rather than trying to overload free functions from std namespace?
Your intent will be clearer and it will be more object orientated.
In fact here is an example of a pretty cookie-cutter event logger I wrote recently, if that helps you to understand the sort of thing I'm talking about. My design allows for dependnacy injection, as well as keeping boring decisions about how something should be formatted as output and where it should go (stdout or file etc) in the logger.
Of course you can define your own cout.
First you need a class which can handle the << operator and contains an fstream and an ostream (like cout).
class logstream
{
private:
fstream *filestream;
ostream *cout;
public:
logstream(fstream* filestream, ostream* cout)
{
this->cout = cout;
this->filestream = filestream;
}
string operator<< (char* s)
{
*cout << s;
*filestream << s;
return s;
}
};
To use this, simply initialize it with cout and a fstream.
fstream lout = fstream("Filename", ios::app);
logstream cout = logstream(&lout, &std::cout);
And now you have what you wanted.
cout << "message";
EDIT: Don't forget to include
#include <iostream>
#include <fstream>
and
using namespace std;

Trouble implementing a line-by-line file parser in C++

I have trouble implementing a simple file parser in C++11 which reads a file line by line and tokenizes the line. It should properly manage its resources. Usage of the parser should be like:
Parser parser;
parser.open("/path/to/file");
std::pair<int> header = parser.getHeader();
while (parser.hasNext()) {
std::vector<int> tokens = parser.getNext();
}
parser.close();
So the Parser class needs one member std::ifstream file (or std::ifstream* file?)
1) How should the constructor initialize this->file?
2) How should the open method set this->file to the input file?
3) How should the next line from the file get loaded into a string?
(Is this what you would use: std::getline(this->file, line)) ?
Can you give some advice? Ideally, could you sketch out the class as a code example.
Since the Parser is probably in a pretty useless state once you've constructed it and before you've opened the file, I would suggest having your use case look something like this:
Parser parser("/path/to/file");
std::pair<int> header = parser.getHeader();
while (parser.hasNext()) {
std::vector<int> tokens = parser.getNext();
}
parser.close();
In which case, you should use the constructor's member initialization list to initialise the file member (which, yes, should be of type std::ifstream):
Parser::Parser(std::string file_name)
: file(file_name)
{
// ...
}
If you kept the constructor and open member function separate, you could just leave the constructor as default because the file member will be default constructed giving you a file stream that is not associated with any file. You would then get Parser::open to forward the file name to std::ifstream::open, like so:
void Parser::open(std::string file_name)
{
file.open(file_name);
}
Then, yes, to read lines from the file, you want to use something similar to this:
std::string line;
while (std::getline(file, line)) {
// Do something with line
}
Good job for not falling into the trap of doing while (!file.eof()).
It can be designed in many ways.
You may ask the user to provide you a stream instead of specifying a filename.
That will be more generic and will work in all streams.
That way you should have a std::ifstream& member variable though you can have a pointer type as well but you need to do *_stream << to invoke any operator.
If you take a file, you mat construct a stream in your constructor and close it if open in destructor
Actually, there is an alternative to feeding the name of the file to Parser: you could feed it a std::istream. What's interesting in this is that this way any derived class of std::istream can be used, and thus you could feed it, for example, a std::istringstream, which makes it easier to write unit-tests.
class Parser {
public:
explicit Parser(std::istream& is);
/**/
private:
std::istream& _stream;
/**/
};
Next, comes iteration. It is not idiomatic in C++ to have a has followed by a get. std::istream supports iteration (with an input iterator), you could perfectly design your parser so it does too. This way you will have the benefit of compatibility with many STL algorithms.
class ParserIterator:
public std::iterator< std::input_iterator_tag, std::vector<int> >
{
public:
ParserIterator(): _stream(nullptr) {} // end
ParserIterator(std::istream& is): _stream(&is) { this->advance(); }
// Accessors
std::vector<int> const& operator*() const { return _vec; }
std::vector<int> const* operator->() const { return &_vec; }
bool equals(ParserIterator const& other) const {
if (_stream != other._stream) { return false; }
if (_stream == nullptr) { return true; }
return false;
}
// Modifiers
ParserIterator& operator++() { this->advance(); return *this; }
ParserIterator operator++(int) {
ParserIterator tmp(*this);
this->advance();
return tmp;
}
private:
void advance() {
assert(_stream && "cannot advance an end iterator");
_vec.clear();
std::string buffer;
if (not getline(*_stream, buffer)) {
_stream = 0; // end of story
}
// parse here
}
std::istream* _stream;
std::vector<int> _vec;
}; // class ParserIterator
inline bool operator==(ParserIterator const& left, ParserIterator const& right) {
return left.equals(right);
}
inline bool operator!= (parserIterator const& left, ParserIterator const& right) {
return not left.equals(right);
}
And with that we can augment our parser:
ParserIterator Parser::begin() const {
return ParserIterator(_stream);
}
ParserIterator Parser::end() const {
return ParserIterator();
}
I'll leave the getHeader method and the actual parsing content to you ;)

Trying to implement an iterator without an explicit container

After my recent question, I am trying to implement my own contrived example.
I have a basic structure in place but even after reading this, which is probably the best tutorial I've seen, I'm still very confused. I think I should probably convert the Chapter._text into a stream and for the increment operator do something like
string p = "";
string line;
while ( getline(stream, line) ) {
p += line;
}
return *p;
but I'm not sure which of the "boilerplate" typedefs to use and how to put all these things together. Thanks much for your help
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Paragraph {
public:
string _text;
Paragraph (string text) {
_text = text;
}
};
class Chapter {
public:
string _text;
/* // I guess here I should do something like:
class Iterator : public iterator<input_iterator_tag, Paragraph> {
}
// OR should I be somehow delegating from istream_iterator ? */
Chapter (string txt_file) {
string line;
ifstream infile(txt_file.c_str());
if (!infile.is_open()) {
cout << "Error opening file " << txt_file << endl;
exit(0);
}
while ( getline(infile, line) ) {
_text += (line + "\n");
}
}
};
int main(int argc, char** argv) {
Chapter c(argv[1]);
// want to do something like:
// for (<Paragraph>::iterator pIt = c.begin(); pIt != c.end(); pIt++) {
// Paragraph p(*pIt);
// // Do something interesting with p
// }
return 0;
}
As you weren't planning on a chapter loading at a time (merely a paragraph), and your paragraph is empty, I think this might be best done with a single paragraph_iterator class
class paragraph_iterator :
public std::iterator<std::input_iterator_tag, std::string>
{
std::shared_ptr<std::ifstream> _infile; //current file
std::string _text; //current paragraph
paragraph_iterator(const paragraph_iterator &b); //not defined, so no copy
paragraph_iterator &operator=(const paragraph_iterator &b); //not defined, so no copy
// don't allow copies, because streams aren't copiable.
// make sure to always pass by reference
// unfortunately, this means no stl algorithms either
public:
paragraph_iterator(string txt_file) :_infile(txt_file.c_str()) {
if (!infile.is_open())
throw std::exception("Error opening file ");
std::getline(_infile, _text);
}
paragraph_iterator() {}
paragraph_iterator &operator++() {
std::getline(_infile, _text);
return *this;
}
// normally you'd want operator++(int) as well, but that requires making a copy
// and std::ifstream isn't copiable.
bool operator==(const paragraph_iterator &b) const {
if (_infile.bad() == b._infile.bad())
return true; //all end() and uninitialized iterators equal
// so we can use paragraph_iterator() as end()
return false; //since they all are seperate strings, never equal
}
bool operator!=(const paragraph_iterator &b) const {return !operator==(b);}
const std::string &operator*() const { return _text;}
};
int main() {
paragraph_iterator iter("myfile.txt");
while(iter != paragraph_iterator()) {
// dostuff with *iter
}
}
the stream is encapsulated in the iterator, so that if we have two iterators to the same file, both will get every line. If you have a seperate Chapter class with two iterators, you may run into "threading" problems. This is pretty bare code, and completely untested. I'm sure there's a way to do it with copiable iterators, but far trickier.
In general, an iterator class implementation is closely tied with the data structure it iterates over. Otherwise, we'd just have a few generic iterator classes.

Avoiding Error Flags when Reading Files

This is how I usually read files with std::ifstream:
while (InFile.peek() != EOF)
{
char Character = InFile.get();
// Do stuff with Character...
}
This avoids the need of an if statement inside the loop. However, it seems that even peek() causes eofbit to be set, which makes calling clear() necessary if I plan on using that same stream later.
Is there a cleaner way to do this?
Typically, you would just use
char x;
while(file >> x) {
// do something with x
}
// now clear file if you want
If you forget to clear(), then use an RAII scope-based class.
Edit: Given a little more information, I'd just say
class FileReader {
std::stringstream str;
public:
FileReader(std::string filename) {
std::ifstream file(filename);
file >> str.rdbuf();
}
std::stringstream Contents() {
return str;
}
};
Now you can just get a copy and not have to clear() the stream every time. Or you could have a self-clearing reference.
template<typename T> class SelfClearingReference {
T* t;
public:
SelfClearingReference(T& tref)
: t(&tref) {}
~SelfClearingReference() {
tref->clear();
}
template<typename Operand> T& operator>>(Operand& op) {
return *t >> op;
}
};
I'm not sure I understand. Infile.peek() only sets eofbit
when it returns EOF. And if it returns EOF, and later read
is bound to fail; the fact that it sets eofbit is an
optimization, more than anything else.