copy and istream_iterator question

G

George

Hi All,

I'm trying to learn c++/stl. I'd like a fancy way to read lines of an
ascii file into vector of stringbufs. I made a first attempt, but the
compiler complains about private constructors in streambuf.

I'd like to use algorithms instead of a loop, but I don't know if that
is possible. Any ideas?
Thanks in advance.

--------------------------------------------------

#include <iostream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

istream& operator>> (istream& is, stringbuf& sb)
{
is.get(sb);
return is;
}

int main()
{
vector<stringbuf> v;
ifstream f;
f.open(__FILE__);
cout << __FILE__ << endl;
istream_iterator<stringbuf> istart(f),iend;
v.insert(v.begin(),istart,iend);
cout << v.size() << endl;

return 0;
}
 
M

mlimber

George said:
Hi All,

I'm trying to learn c++/stl. I'd like a fancy way to read lines of an
ascii file into vector of stringbufs. I made a first attempt, but the
compiler complains about private constructors in streambuf.

I'd like to use algorithms instead of a loop, but I don't know if that
is possible. Any ideas?
Thanks in advance.

--------------------------------------------------

#include <iostream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

istream& operator>> (istream& is, stringbuf& sb)
{
is.get(sb);
return is;
}

int main()
{
vector<stringbuf> v;
ifstream f;
f.open(__FILE__);
cout << __FILE__ << endl;
istream_iterator<stringbuf> istart(f),iend;
v.insert(v.begin(),istart,iend);
cout << v.size() << endl;

return 0;
}

Since you describe yourself as a C++/STL new-comer, I'll recommend that
you drop manipulating stringbufs and just go with strings. Then you can
do something like this:

#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
using namespace std;

int main()
{
ifstream f( "text.txt" );
if( !f ) return -1;

vector<string> v;
copy( istream_iterator<string>( f ),
istream_iterator<string>(),
back_inserter( v ) );

// Now v contains all the strings from f
// ...
return 0;
}

I'd suggest you pick up Koenig and Moo's _Accelerated C++_, the best
book for learning STL-based C++ programming from the ground up, and
Josuttis' _The C++ Standard Library - A Tutorial and Reference_.

Cheers! --M
 
N

Neil Cerutti

Hi All,

I'm trying to learn c++/stl. I'd like a fancy way to read
lines of an ascii file into vector of stringbufs. I made a
first attempt, but the compiler complains about private
constructors in streambuf.

I'd like to use algorithms instead of a loop, but I don't know
if that is possible. Any ideas? Thanks in advance.

Here's a program closely modeled on yours, using std::string
instead of std::stringbuf, and std::copy.

#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
std::vector<std::string> v;
std::ifstream f(__FILE__);
std::cout << __FILE__ << '\n';
std::istream_iterator<std::string> start(f), finish;
std::copy(start, finish, std::back_inserter(v));
std::cout << v.size() << '\n';
return 0;
}

You don't need to use stringbuf to use istream_iterator. Perhaps
you needed it for something else.

You can pass the filename to the constructor of the file streams.
If the file is not found, an exception will be thrown.

Check out back_inserter, and some of the other adaptors.

You normally don't want to insert into a vector, unless it's at
the end iterator. A back_inserter calls push_back, which is the
most efficient way to build up a vector.

There are other ways to count the strings in a file that won't
need to build up a vector. Here's one:

#include <fstream>
#include <string>
#include <algorithm>
#include <functional>

template <typename T>
struct yes: std::unary_function<T, bool>
{
bool operator()(const T&) const { return true; }
};

int main()
{
std::ifstream f(__FILE__);
std::cout << __FILE__ << '\n';
std::istream_iterator<std::string> start(f), finish;
std::cout << std::count_if(start, finish, yes<std::string>()) << '\n';
return 0;
}

You could also write your own stateful functor and use
std::for_each. I believe the standard doesn't actually bless this
practice... yet. The problem is that implementations aren't
prohibited form copying your functor. In practice, you're very
unlikely to face problems.
 
G

George

Wow Neil, this is great stuff.

But istream_iterator<string> just takes word by word, delimiting on
spaces. Is there a way to read the whole line into a string?

What is the difference between copy(,,back_inserter<v>) and
v.insert(v.begin(),,)?

Well, I'll not push my graces. Thanks much for listening.

Sincerely, George
 
B

BobR

George wrote in message ...
Wow Neil, this is great stuff.

But istream_iterator<string> just takes word by word, delimiting on
spaces. Is there a way to read the whole line into a string?

Delimit on '\n', or use getline():

// includes here
int main(){
std::vector<std::string> vStr;
std::ifstream in(__FILE__);
if( not in ){ /* throw std::exception(); */ return EXIT_FAILURE;} //if(!in)
std::string line;
while( getline( in, line ) ){ // load the file
vStr.push_back(line);
} // while()
// do something with vStr here.
return 0;
} // main() end
What is the difference between copy(,,back_inserter<v>) and
v.insert(v.begin(),,)?

About 10 seconds per mil on an 33Mhz machine. said:
Well, I'll not push my graces. Thanks much for listening.
Sincerely, George

--
Bob R
POVrookie
--
Dev-C++ IDE: http://www.bloodshed.net/
MinGW (GNU compiler): http://www.mingw.org/
MinGWStudio http://www.parinyasoft.com/
wxWidgets URL: http://www.wxwidgets.org
V IDE & V GUI: http://www.objectcentral.com/
Quincy IDE 2005 URL: http://pipou.net/down/Quincy2005Project.zip
POVray: http://www.povray.org/
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
 
J

Jerry Coffin

George said:
Wow Neil, this is great stuff.

But istream_iterator<string> just takes word by word, delimiting on
spaces. Is there a way to read the whole line into a string?

Yes -- a couple of them. A fairly simple one is to define a proxy class
for the purpose:

class line {
std::string buffer;
public:
friend operator>>(std::istream &is, line &li) {
std::getline(is, li);
return is;
}
operator std::string() const { return buffer; }
};

Extracting an object of type line reads an entire line. In most cases,
you'll immediately convert the result to a std::string, something like:

std::vector<std::string> raw_data;

std::copy(
std::istream_iterator<line>(stream),
std::istream_iterator<line>(),
std::back_inserter(raw_data));

A completely different method is to define a ctype facet that only
classifies new-line and possibly carriage return (but NOT space, tab,
etc.) as whitespace. You then use imbue to make the stream use a locale
including this facet. The normal operator>> for std::string reads
whitespace delimited sequences, so if only new-lines are whitespace,
that means it reads entire lines instead of words. While this second
method works perfectly well, I generally prefer the proxy. The primary
time for considering the ctype is if you consistently need to treat
data a line at a time.
 

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

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top