Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

copy and istream_iterator question

11 views
Skip to first unread message

George

unread,
Dec 15, 2005, 10:44:38 PM12/15/05
to
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;
}

mlimber

unread,
Dec 16, 2005, 9:07:57 AM12/16/05
to

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

Neil Cerutti

unread,
Dec 16, 2005, 9:33:32 AM12/16/05
to
On 2005-12-16, George <george...@excite.com> wrote:
> 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.

--
Neil Cerutti

George

unread,
Dec 16, 2005, 5:47:44 PM12/16/05
to
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

BobR

unread,
Dec 16, 2005, 6:21:00 PM12/16/05
to

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. <G>

>
>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/


Jerry Coffin

unread,
Dec 17, 2005, 5:41:08 PM12/17/05
to
George wrote:
> 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.

--
Later,
Jerry.

George

unread,
Dec 19, 2005, 2:10:28 PM12/19/05
to
Awesome all. Thanks so much for the solutions.

0 new messages