开发者

How do all the different size types relate to each other?

Currently I have a scenario where I want to check whether writing a given string to a filestream will grow the file beyond a given size (this is used for logfile rotation). Now, std::ofstream::tellp开发者_运维问答() returns a streampos, but std::string::size() returns a size_t. The effect is, that this does not work:

out_stream.tellp() + string.size() < limit

because apparently there is an ambiguous overload of operator + for these types. This leads me to two questions:

  1. How can I resolve the above ambiguity?
  2. How do all the different types (size_t, streamsize, streampos, streamoff) relate to each other? When can they be safely converted, and what are possible pitfalls. I am generally confused about these types. All I know is that they are implementation dependent, and that they make certain guarantees (e.g. size_t is always large enough to hold the size of the larges object that would fit into memory on the architecture for which the application was compiled), but what are the guarantees concerning interoperability of these types (see example above, or comparing a streamsize to a size_t)?


You should be able to convert the result from tellp to a std::string::size_type by casting.

static_cast<std::string::size_type>(out_stream.tellp()) + string.size() < limit

EDIT: This is safe because your stream offset will never be negative and will safely convert to an unsigned value.


The real question is: what is the type of limit? The usual way of testing if there is still room is usually: limit - out_stream.tellp() >= string.size() But you have to ensure that limit has a type from which out_stream.tellp() can be subtracted.

In theory, streampos isn't convertable nor comparable to an integral type, or that, converted to an integral type, it gives significant information. And it needed support subtraction, or comparison, for that matter. In practice, I don't think you have to worry too much about the conversion to an integral type existing, and being monotonic (although perhaps on some exotic mainframe...). But you can't be sure that arithmetic with it will work, so I'd probably prefer converting it explicitly to a streamsize (which is guaranteed to be a signed integral type). (Regardless of how you approach the problem, you'll have to deal with the fact that string.size() returns a size_t, which is required to be unsigned, whereas streamsize is required to be signed.)

With regards to your second question: size_t is a typedef to an unsigned integral type, large enough to specify the size of any possible object, streamsize is a typedef to a signed integral type, large enough to specify the size of an "object" in a stream, streamoff is a typedef to an integral type capable of specifying the position of a byte in a file, and streampos is a typedef to fpos, where something is a type which can be used to maintain the state in the case of a multibyte stream. The standard makes very few requirements concerning the relationships between them (and some of the few it makes are mathematically impossible to realize), so you're pretty much on your own.


I believe the standard says that streamsize is implementation-specific, so no help there. For a practical answer, you can check the headers where these are typedefed.

Considering that size_t might be 4 bytes while your application could conceivably operate on a stream of more than 4GB length, I believe that you should cast to a known-good-size type for interoperating for an airtight solution.

Of course, if you know (maybe with a compile-time assertion) that size_t or streamsize is 8 bytes long, you can use that type directly. If you have a stream whose length doesn't fit in 8 bytes, you have more serious problems than casting to the right type.


If you have big sizes, isn't unsigned long long the best you can get. If that isn't big enough, what else is?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜