memstream discussion (was Re: strstream reinstatement)
werasm ha scritto:
How about having a new stream type that forces this issue. You have to
provide the size of the buffer. This is most often known at compile
time, therefore:
void output()
{
omemstream<BUFLEN> stream;
stream << "Integer Set: " << 5 << ", " << 10 << ", etc. "
<< std::endl;
c_legacy_function_that_reads_buffer( stream.c_str(), stream.length()
);
//length() returns bytes streamed, size() return BUFLEN?
}
I don't find it very attractive to have the memstream own the buffer
because there would still be use-case scenarios where a copy of the
entire buffer is required. That is one thing that my proposal precisely
tries to avoid. In particular, in the input case you would always
require to copy the input data, but also in output case you might need
to copy the output data. Consider this case and how it's handled with my
proposed interface:
struct LegacyStruct
{
char s[BUFLEN];
int p;
};
void foo()
{
LegacyStruct ls;
omemstream formatter(&ls.s, BUFLEN);
formatter << /* something here */ << ends; // appends null terminator!
if(!formatter)
// buffer overflow! do something here
ls.p = 12345;
legacy_function(&ls);
}
With your proposed interface, I would need to copy the data out of the
memstream and into ls.s.
I think it would be good to discern also, between a stream that adds a
NULL terminator by default, and one that does not. This could be an
instantiation option with the default choice being the safer route. For
safety purposes implementations could also specify the actual size to
be one greater than BUFLEN, and force the last to remain NULL
terminated and untouched.
template <unsigned size>
class X
{
enum{ StreamSz = size+1 }
char buffer_[StreamSz];
};
I disagree that nulls should have a special treatment. That would make
the interface more complex and, in the end, the design would be as
error-prone as not providing the feature at all. For what's worth, just
look how easily I handled the null terminator in the example above.
I have not looked at your proposal, but could this be considered?
Unfortunately the link I posted in my previous post is no longer valid.
I have a submitted a heavily revised paper to the committee, I don't
know how long it will take for it to be available to the public. In case
you are interested, I can send it to you directly.
Carl Barron ha scritto:
In article <1157636428.873405.22210@m79g2000cwm.googlegroups.com>,
werasm <w_erasm@telkomsa.net> wrote:
A lot of the excess copying can be avoid by being less terse,by
using a default constructed stringstream and copying with
an ostreambuf_iterator<char> to the stream and then seeking the
beginning read [seekg(0)] and then reading the stream.
Precisely: you can avoid a lot of the excess copying, but the point here
is to avoid *all* copying *plus* avoiding the automatic buffer
management provided by stringstream. What's the point in having the
stringstream allocate a dynamically-sized buffer (something that might
require multiple accesses to the heap -> expensive) when you know in
advance the maximum size of the buffer and you already have a suitable
buffer already allocated?
As you see, passing std::string objects around is a nuisance that I aim
to avoid but it's not the only reason that makes, IMHO, this proposal
interesting.
prepending an ostream can be read into a properly sized char array
or vector<char> via std::copy(std::istreambuf_iterator<char>
(stream),...);
<snip>
initializing a string stream form a '\0' terming terminated char
array does not need to be converted to a string first, since something
like
<snip>
note this does no unnecessary conversions to std::string.
I hope you are not saying that that is a valid workaround! The goal is
to try to make life easier to the user. I don't think any programmer
would like to write that... (at least I don't).
seems like the only thing is simple usages that can be handled simple
stream buffers that don't seek, if you don't seek the stream
[seekp,seekp] then the streambuf's defaults [always fail] will work.
so only thing needed is a constructor to set the buffer and end()
function for output only memory buf
struct isimplemembuf:std::streambuf
{
isimplemembuf(char *start,std::ptrdiff_t size)
{setg(start,start,start+size}
char *begin() {return eback();}
char *end() {return egptr();}
};
struct osimplemembuf:std::streambuf
{
osimplemembuf(char *start,std::ptrdiff_t size)
{ setp(start,start+size);}
char *begin() {return pbase();}
char *end() {return pptr();}
};
look simple enough:)
The seekpos and seekoff functions can be written if needed.
Tedious but not complicated...
Yes, that's the idea, but I prefer having only one streambuf-derived
class able to manage both the input and output sequences. I did not
include begin/end as I don't see a valid reason for having them. It's
not that hard actually to provide seek support, so my proposal provides
that and little more. The proposal contains a working complete
implementation too.
Ganesh
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]