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

copying from an input stream into a string

54 views
Skip to first unread message

glen stark

unread,
Sep 10, 2014, 6:42:11 AM9/10/14
to
Hi everyone.

I'm in the position that I have an input stream, start_pos, and end_pos,
and I'd like to copy the contents of the stream from start_pos to end_pos
into a string.

I can think of a number of ways to do this, but I don't like any of
them. What do you think is the most elegant way to do this?

Thanks,

Victor Bazarov

unread,
Sep 10, 2014, 8:34:02 AM9/10/14
to
It must be by means of std::copy.

V
--
I do not respond to top-posted replies, please don't ask

Juha Nieminen

unread,
Sep 10, 2014, 10:24:41 AM9/10/14
to
std::copy with a std::back_inserter.

It might not be the most *efficient* implementation, but it's fairly
short, simple and elegant.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Victor Bazarov

unread,
Sep 10, 2014, 2:18:56 PM9/10/14
to
On 9/10/2014 8:33 AM, Victor Bazarov wrote:
> On 9/10/2014 6:41 AM, glen stark wrote:
>> I'm in the position that I have an input stream, start_pos, and end_pos,
>> and I'd like to copy the contents of the stream from start_pos to
>> end_pos
>> into a string.
>>
>> I can think of a number of ways to do this, but I don't like any of
>> them. What do you think is the most elegant way to do this?
>
> It must be by means of std::copy.

Or perhaps by means of one of c-tors. Standard string has a constructor
from two input iterators (see 21.4.2/14), so if you can convert the
positions into iterators, you could simply construct the string from them.

woodb...@gmail.com

unread,
Sep 10, 2014, 10:03:09 PM9/10/14
to
I use this constructor sometimes:

string (const char* s, size_t n);

Copies the first n characters from the array of characters pointed by s.

I got the reference info from cplusplus.com


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
Message has been deleted

Victor Bazarov

unread,
Sep 11, 2014, 8:50:55 AM9/11/14
to
On 9/11/2014 7:58 AM, Stefan Ram wrote:
> glen stark <g.a....@gmail.com> writes:
>> I can think of a number of ways to do this, but I don't like any of
>> them. What do you think is the most elegant way to do this?
>
> The constructor+iterator combination is elegant, but the fastest
> way is to get the filesize and then pre-allocate a buffer.
>
> Getting the filesize is difficult. [..]

Who said it was a file?

Luca Risolia

unread,
Sep 11, 2014, 3:19:19 PM9/11/14
to
Try this:

http://www.linux-projects.org/listing/cpp_solutions/20.5/main.cpp

Below is the code:

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

namespace mystd {

template<class Cont> class back_insert_iterator;

/*
* Base class for all the back_insert_iterator's. It requires
* a back_insert_iterator class as template argument.
*/
template<class Cont, class Derived = back_insert_iterator<Cont> >
class back_insert_iterator_base : public
std::iterator<std::output_iterator_tag, void, void, void, void> {
protected:
Cont& container;

explicit back_insert_iterator_base(Cont& c) : container(c) { }

public:
typedef Cont container_type;

Derived& operator=(typename container_type::const_reference v) {
container.push_back(v);
return *(static_cast<Derived*> (this));
}

Derived& operator++() {
return *(static_cast<Derived*> (this));
}

Derived& operator++(int) {
return *(static_cast<Derived*> (this));
}

Derived& operator*() {
return *(static_cast<Derived*> (this));
}
};

/*
* Generic back_insert_iterator for any container
*/
template<class Cont>
class back_insert_iterator : public back_insert_iterator_base<Cont> {
public:

explicit back_insert_iterator(Cont& c) :
back_insert_iterator_base<Cont> (c) { }
using back_insert_iterator_base<Cont>::operator =;
};

/*
* Specialized class for a basic_string's:
* this class adds one more operator=() implementing string concatenation
*/
template<class Ch, class Tr, class A>
class back_insert_iterator<std::basic_string<Ch, Tr, A> > : public
back_insert_iterator_base<std::basic_string<Ch, Tr, A> > {
public:

explicit back_insert_iterator(std::basic_string<Ch, Tr, A>& c) :
back_insert_iterator_base<std::basic_string<Ch, Tr, A> > (c) { }
using back_insert_iterator_base<std::basic_string<Ch, Tr, A>
>::operator =;

back_insert_iterator& operator=(const std::basic_string<Ch, Tr, A> &
s) {
back_insert_iterator_base<std::basic_string<Ch, Tr, A>
>::container.append(s);
return *this;
}
};

/*
* This is convenience function. It returns a back insert iterator
* for a container without requiring us to specify any template argument.
*/
template <class Cont> back_insert_iterator<Cont> back_inserter(Cont& c) {
return back_insert_iterator<Cont > (c);
}
}

int main(int argc, char** argv) {
// Two examples
using namespace std;
typedef basic_string<char> String;
vector<String > v;
copy(std::istream_iterator<String > (std::cin),
std::istream_iterator<String > (), mystd::back_inserter(v));
String s;
copy(v.begin(), v.end(), mystd::back_inserter(s));
cout << s;
return 0;
}

Paavo Helde

unread,
Sep 11, 2014, 4:10:23 PM9/11/14
to
r...@zedat.fu-berlin.de (Stefan Ram) wrote in news:slurp-20140911135058
@ram.dialup.fu-berlin.de:

> glen stark <g.a....@gmail.com> writes:
>>I can think of a number of ways to do this, but I don't like any of
>>them. What do you think is the most elegant way to do this?
>
> The constructor+iterator combination is elegant, but the fastest
> way is to get the filesize and then pre-allocate a buffer.

If it is a file, then the fastest way to get it into memory is to use
memory mapping. Some might claim this is also the most elegant way ;-)

Cheers
Paavo
0 new messages