istream trouble

  • Thread starter Alexander Stippler
  • Start date
A

Alexander Stippler

I'm no expert to streams, so I need some help with the following program.
It takes a text file as input and reads the characters contained into a
std::vector<char>. But it does not work correctly. Giving it a file containing
just one letter, this letter gets inserted into the list twice. Why and how
to correct it? Here is the code:

#include <fstream>
#include <vector>
#include <stringstream>
#include <string>

template <typename T>
std::vector<T>
readParameterList(std::ifstream &in)
{
std::vector<T> ret;
std::string line;
T value;

getline(in, line);
std::istringstream lineStream(line);
while (!lineStream.eof()) {
lineStream >> value;
ret.push_back(value);
}
return ret;
}


int
main()
{
std::ifstream is("checkIt");
std::vector<char> v = readParameterList<char>(is);

std::cerr << v.size() << std::endl;
}

P.S.: the function shall work for other built-in types too, so it's a
template function.

regards,
Alex
 
T

Thomas Matthews

Alexander said:
I'm no expert to streams, so I need some help with the following program.
It takes a text file as input and reads the characters contained into a
std::vector<char>. But it does not work correctly. Giving it a file containing
just one letter, this letter gets inserted into the list twice. Why and how
to correct it? Here is the code:
[snip]
template <typename T>
std::vector<T>
readParameterList(std::ifstream &in)
{
std::vector<T> ret;
std::string line;
T value;

getline(in, line);
std::istringstream lineStream(line);
while (!lineStream.eof()) {
lineStream >> value;
ret.push_back(value);
}

Change the above while loop to:
while (lineStream >> value)
{
ret.push_back(value);
}
The FAQ (listed below) explains the reasons
behind this correction.
return ret;
}
[snip]

regards,
Alex



--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book
http://www.sgi.com/tech/stl -- Standard Template Library
 
N

namespace

Alexander said:
while (!lineStream.eof()) {
lineStream >> value;
ret.push_back(value);
}
return ret;
}

Instead of checking for eof then reading a char, read a char then check
for eof. Also, to be safe use fail instead of eof, or operator bool.

while (true) {
lineStream >> value;
if (lineStream.fail()) break;
ret.push_back(value);
}
return ret;
}
 
D

davidrubin

Alexander said:
template <typename T>
std::vector<T>
readParameterList(std::ifstream &in)
{
std::vector<T> ret;
std::string line;
T value;

getline(in, line);
std::istringstream lineStream(line);
while (!lineStream.eof()) {
lineStream >> value;
ret.push_back(value);
}
return ret;
}

Rather than templatize the function on T, templatize it on a
'std::back_insert_iterator':

template <typename T>
int readParameterList(std::back_insert_iterator<T> it,
std::istream& stream);
// Load into a container using the specified back insertion
// iterator 'it' values read from the specified 'stream',
// having the format
//..
// value1 value2 value3 ...
//..
// Return the non-negative number of values read on success,
// and a negative value otherwise.

This function can be implemented as

template <typename T>
T::size_type readParameterList(std::back_insert_iterator<T> it,
std::istream& stream)
{
T::value_type value;
T::size_type numElements = 0;

while (stream >> value) {
*it++ = value;
++numElements;
}
return numElements;
}

and called as, e.g.,

typedef std::deque<float> ParameterList;
ParameterList parameters;
std::ifstream ifs("checkIt");
if (ifs) {
ParameterList::size_type n =
readParameterList(std::back_inserter(parameters), ifs);
//...
}

/david
 
D

davidrubin

Rather than templatize the function on T, templatize it on a
'std::back_insert_iterator':

template <typename T>
int readParameterList(std::back_insert_iterator<T> it,
std::istream& stream);

Sorry. What I meant is templatize the function on the container type T,
rather than the element type T, and parametize the function by a
'std::back_insert_iterator' of type T. This lets you use any container
that supports 'push_back'. It is more efficient than returning a
container by value.
/david
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,805
Latest member
ClydeHeld1

Latest Threads

Top