By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,417 Members | 1,111 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,417 IT Pros & Developers. It's quick & easy.

copy and istream_iterator question

P: n/a
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;
}

Dec 16 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
George 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.

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

#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

Dec 16 '05 #2

P: n/a
On 2005-12-16, George <ge**********@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
Dec 16 '05 #3

P: n/a
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

Dec 16 '05 #4

P: n/a

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/
Dec 16 '05 #5

P: n/a
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.

Dec 17 '05 #6

P: n/a
Awesome all. Thanks so much for the solutions.

Dec 19 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.