copy and istream_iterator question

Discussion in 'C++' started by George, Dec 16, 2005.

  1. George

    George Guest

    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;
    }
     
    George, Dec 16, 2005
    #1
    1. Advertising

  2. George

    mlimber Guest

    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
     
    mlimber, Dec 16, 2005
    #2
    1. Advertising

  3. George

    Neil Cerutti Guest

    On 2005-12-16, 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.


    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
     
    Neil Cerutti, Dec 16, 2005
    #3
  4. George

    George Guest

    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
     
    George, Dec 16, 2005
    #4
  5. George

    BobR Guest

    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/
     
    BobR, Dec 16, 2005
    #5
  6. George

    Jerry Coffin Guest

    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.
     
    Jerry Coffin, Dec 17, 2005
    #6
  7. George

    George Guest

    Awesome all. Thanks so much for the solutions.
     
    George, Dec 19, 2005
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Bill Rudolph

    istream_iterator question

    Bill Rudolph, Aug 14, 2003, in forum: C++
    Replies:
    4
    Views:
    560
    Bill Rudolph
    Aug 15, 2003
  2. Chris Mantoulidis
    Replies:
    2
    Views:
    429
  3. Replies:
    26
    Views:
    2,160
    Roland Pibinger
    Sep 1, 2006
  4. Pradeep
    Replies:
    5
    Views:
    1,109
    =?ISO-8859-1?Q?Jens_M=FCller?=
    Oct 19, 2006
  5. Replies:
    8
    Views:
    487
    James Kanze
    Sep 19, 2011
Loading...

Share This Page