6

I'm pretty familiar with most of C++ but one area I've avoided has been IO streams, mainly because I've been using it on embedded systems where they're not appropriate. Recently I've had to become familiar with them, however, and I'm struggling to figure out something that I feel should be simple.

What I'm looking for a relatively efficient way to read a fixed number of characters from a C++ stream into a std::string. I could easily read into a temporary char array with the read() method and convert that into a std::string, but that's fairly ugly and involves a wasteful copy. I could also read the whole of a stream into a string with something like this:

std::string getFile(std::fstream &inFile)
{
    std::stringstream buffer;
    buffer << inFile.rdbuf();
    return buffer.str();
}

... But unbounded reads into memory are generally a poor idea, so I'd really like to access the file one block at a time, say 4K or so. I could also read character at a time, but that just feels both uglier and less efficient than reading into a temporary char array.

So, is there a simple way to get a std::string directly from a stream which contains the next N characters from the stream? It may well be that there is simply no way to do this, but it seems strange to me that such a thing would be missing so I felt I must be missing something glaringly obvious.

By the way, I'm quite familiar with the C file IO APIs and I'm not looking for a solution involving them. I could knock something up with read() and write(), but the code I'm working with makes heavy use of streams and I think it's good practice to keep my code additions in a consistent style.

Cartroo
  • 4,233
  • 20
  • 22
  • See [this](http://stackoverflow.com/questions/9521629/stdstringss-capacity-reserve-resize-functions) and [this](http://stackoverflow.com/questions/14286526/the-usage-of-stringreserve) too. – Suvarna Pattayil Apr 08 '13 at 15:55

1 Answers1

9

You are on the right track. :)

mystring.resize( 20 );
stream.read( &mystring[0], 20 );

Edit:

In C++11. this is well-defined and safe. Unlike data() and c_str(), std::string::operator[] provides a mutable reference to the underlying data.

In C++03, It is safe in a practical sense, but the definition of std::string was too weak to guarantee this safety. C++03 allowed string data to be non-contiguous, but I don't believe any available implementation ever took advantage of that.

Community
  • 1
  • 1
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • @Nawaz I was rather shocked when it came to mine. :) – Drew Dormann Apr 08 '13 at 15:53
  • I know *the feeling* when such tricky ideas come to mind and makes your life easy! – Nawaz Apr 08 '13 at 15:54
  • Yes, that looks like it'll work, but is it safe? For example, writing to the result of [`data()`](http://en.cppreference.com/w/cpp/string/basic_string/data) or [`c_str()`](http://en.cppreference.com/w/cpp/string/basic_string/c_str) is undefined behaviour, as far as I was aware. I'm not sure if this would mess around with, for example, the GNU STL's copy-on-write semantics for the underlying character buffer. Can anybody provide evidence that this is in fact a safe operation on most platforms? [This page](http://en.cppreference.com/w/cpp/string/basic_string/operator_at) seems to say not... – Cartroo Apr 08 '13 at 16:06
  • 2
    @Cartroo, read the page carefully, the notes only apply when you're referencing the character one past the end of the string. That won't happen in this case. Copy-on-write strings aren't allowed in C++11, see http://stackoverflow.com/questions/12199710/legality-of-cow-stdstring-implementation-in-c11. – Mark Ransom Apr 08 '13 at 16:18
  • Yes, thanks Mark, I just spotted that myself - apologies for not reading carefully enough. After a little poking around with the GNU STL, it appears that calling `c_str()` or `data()` don't adjust the underlying pointer, and changes affect other copies as you'd expect with a CoW system. However, calling the non-`const` `operator[]` does indeed seem enough to trigger a copy operation so writes should be quite safe. Thanks for the help. – Cartroo Apr 08 '13 at 16:20