# Reading n chars from stream to string

I need to read n chars from a binary file into a string. Currently, what I do is:

static string Read(istream &stream, uint32_t count)
{
auto bytes = unique_ptr<char[]>(new char[count]);

return string(bytes.get(), count);
}


I found the way I deal with the array of chars quite messy. If I used new and delete[] directly, it would make the code messy in another way (I would need to add a local variable for the result). And I'm trying to avoid delete as a general rule.

Is there a clear way to write this code? The fact that it uses twice as much memory as it needs is probably not a big deal, but fixing that would be nice too.

• I think this is actually quite clean – albeit low-level – code. Nothing really wrong with it, and it’s probably more efficient than ruds’ implementation, although that’s arguably even cleaner. – Konrad Rudolph Jul 20 '13 at 13:51
• @KonradRudolph: There is no need to be calling new here. Especially since the string object will deal with all that for you. – Martin York Jul 20 '13 at 21:48
• @Loki Ah true, I’d completely forgotten about C++11’s contiguity requirement. – Konrad Rudolph Jul 20 '13 at 22:03

Why not:

static string Read(istream &stream, uint32_t count)
{
std::string result(count, ' ');

return result;
}


Though not strictly C++03 compatible that is easily validated. One of the reasons the committee found it easy to add the new constraint in C++11 was that no implementation did not use contiguous memory (Random Access Iterators are a hint).

But a C++03 strict implementation would be:

static string Read(istream &stream, uint32_t count)
{
std::vector<char> result(count);  // Because vector is guranteed to be contiguous in C++03

return std::string(&result[0], &result[count]);
}

• Yeah, that's certainly better. – svick Jul 20 '13 at 21:57
• Note that this requires C++11 in a non-obvious way (C++03 didn't require that &result[0] worked this way). Otherwise, LGTM. – ruds Jul 20 '13 at 22:12
• Depending on your use case, you may want to do result.resize(stream.gcount());, in case not all of count bytes could be read. – Josh Kelley Apr 21 '15 at 18:40

First of all, it seems that you've got a using namespace std; somewhere in your code. Don't do that. (No, really).

Here's a function that should meet your needs.

static std::string Read(std::istream &stream, std::string::size_type count)
{
std::string out;
out.reserve(count);
std::copy_n(std::istreambuf_iterator(stream), count, std::back_inserter(out));
return out;
}

• uint32_t should have an std:: as well. – Jamal Jul 19 '13 at 20:07
• I don't have using namespace std; there. Instead, I have using std::uint32_t; using std::unique_ptr; using std::string; using std::istream; there. It's kind of annoying, but I thought it would be better than writing std:: everywhere. – svick Jul 19 '13 at 20:12
• @Jamal You're right. Actually, I've changed it to std::string::size_type, as that's the size class we're interested in. – ruds Jul 19 '13 at 20:13
• @svick I think it's odd to read code with names from std but with no std:: in front. Personal tastes vary, of course. – ruds Jul 19 '13 at 20:14
• Is this going to insert the characters one by one? I worry that doing that would be too slow (the result might be one megabyte or so). (Of course, the proper way to find that out would be to measure it.) – svick Jul 19 '13 at 20:18