I need to read n char
s 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]);
stream.read(bytes.get(), count);
return string(bytes.get(), count);
}
I found the way I deal with the array of char
s 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.
-
\$\begingroup\$ 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. \$\endgroup\$Konrad Rudolph– Konrad Rudolph2013年07月20日 13:51:19 +00:00Commented Jul 20, 2013 at 13:51
-
\$\begingroup\$ @KonradRudolph: There is no need to be calling new here. Especially since the string object will deal with all that for you. \$\endgroup\$Loki Astari– Loki Astari2013年07月20日 21:48:13 +00:00Commented Jul 20, 2013 at 21:48
-
\$\begingroup\$ @Loki Ah true, I’d completely forgotten about C++11’s contiguity requirement. \$\endgroup\$Konrad Rudolph– Konrad Rudolph2013年07月20日 22:03:40 +00:00Commented Jul 20, 2013 at 22:03
2 Answers 2
Why not:
static string Read(istream &stream, uint32_t count)
{
std::string result(count, ' ');
stream.read(&result[0], 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
stream.read(&result[0], count);
return std::string(&result[0], &result[count]);
}
-
\$\begingroup\$ Yeah, that's certainly better. \$\endgroup\$svick– svick2013年07月20日 21:57:19 +00:00Commented Jul 20, 2013 at 21:57
-
3\$\begingroup\$ Note that this requires C++11 in a non-obvious way (C++03 didn't require that &result[0] worked this way). Otherwise, LGTM. \$\endgroup\$ruds– ruds2013年07月20日 22:12:38 +00:00Commented Jul 20, 2013 at 22:12
-
\$\begingroup\$ Depending on your use case, you may want to do
result.resize(stream.gcount());
, in case not all ofcount
bytes could be read. \$\endgroup\$Josh Kelley– Josh Kelley2015年04月21日 18:40:42 +00:00Commented Apr 21, 2015 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;
}
-
1\$\begingroup\$
uint32_t
should have anstd::
as well. \$\endgroup\$Jamal– Jamal2013年07月19日 20:07:19 +00:00Commented Jul 19, 2013 at 20:07 -
\$\begingroup\$ I don't have
using namespace std;
there. Instead, I haveusing 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 writingstd::
everywhere. \$\endgroup\$svick– svick2013年07月19日 20:12:02 +00:00Commented Jul 19, 2013 at 20:12 -
3\$\begingroup\$ @Jamal You're right. Actually, I've changed it to std::string::size_type, as that's the size class we're interested in. \$\endgroup\$ruds– ruds2013年07月19日 20:13:32 +00:00Commented Jul 19, 2013 at 20:13
-
\$\begingroup\$ @svick I think it's odd to read code with names from
std
but with nostd::
in front. Personal tastes vary, of course. \$\endgroup\$ruds– ruds2013年07月19日 20:14:13 +00:00Commented Jul 19, 2013 at 20:14 -
\$\begingroup\$ 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.) \$\endgroup\$svick– svick2013年07月19日 20:18:55 +00:00Commented Jul 19, 2013 at 20:18