views:

81

answers:

4

So istringstream copies the contents of a string when initialised, e.g

string moo("one two three four");
istringstream iss(moo.c_str());

I was wondering if there's a way to make std::istringstream use the given c_str as its buffer without copying things. This way, it wont have to copy large bits of memory before passing the std::istringstream& to functions that take istream& as an argument.

What I've been trying to do is converting some functions which only take std::ifstream& arguments (they're mostly parsers) into taking istream& as well. Would I have to make my own istream subclass for this?

+1  A: 

There's only a copy because the parameter you pass, a const char*, requires conversion to the argument type of the istringstream constructor.

Just pass in the string without calling c_str().

istringstream iss(moo);

Well ok, that doesn't prevent copying completely, but it eliminates an unnecessary copy. To completely eliminate the copy, you'd have to rewrite std::stringbuf, which specifically avoids working directly on the string you give it.

Ben Voigt
+2  A: 

It depends on what a std::string does. According to 27.2.1/1 The class basic_istringstream<charT,traits,Allocator> ... uses a basic_stringbuf<charT,traits,Allocator> object to control the associated storage. Since the class must use an object it must copy construct the string into that object.

So the real question is not whether a stringstream copies the contents, but whether copy constructing a string will copy the contents or implement some sort of copy-on-write scheme.

R Samuel Klatchko
+2  A: 

the deprecated istrstream supports this feature.

#include <string>
#include <strstream>
using namespace std;

int main(int argc, char* argv[])
{
    string moo = "one two three four";
    istrstream istr(const_cast<char*>(moo.c_str()),moo.size());
    std::string line;
    while(!istr.fail() && !istr.eof()){
        getline(istr,line,' ');
        cout << line << "_";
    }
    // prints: one_two_three_four_
}
smerlin
Using `capacity()` is wrong, this should be `size()`.
sbi
@sbi: my bad, i did some tests with strstream first, was a leftover from that, well its fixed now.
smerlin
+2  A: 

It's fairly trivial to write a basic std::streambuf class that reads from a given memory area. You can then construct an istream from this and read from that.

http://stackoverflow.com/questions/1448467/initializing-a-c-stdistringstream-from-an-in-memory-buffer/1449527#1449527

Note that the lifetime of the buffer pointed to be c_str() is very limited, though, and there's no guarantee that a call to c_str() want cause some copying although I don't know of any implementations where it does.

Charles Bailey
Ah, thanks for that, will give that a try. It looks a lot simpler than what I imagined it would be :)
kamziro