ostream operator<< and builtin types

E

Erik Wikström

Accordin to the standard it is possible for
basic_ostream::eek:perator<<(T val), where T is a builtin arithmetic
type, to fail (and optionally throw an exception. I've been trying to
track down what would cause << to fail but have not yet been
successful, what I really want to know is whether one should bother
looking for exceptions when using code such as this to convert
arithmetic types to strings:

template<typename T>
std::string atos(const T& v)
{
std::eek:stringstream os;
if (!(os << v))
throw std::runtime_exception("Failed to convert value");
return os.str();
}

While I realise that it might be a good idea to check when converting
user defined types I hope/assume that there are no implementations out
there that would fail to convert the builtin arithmetic types (except
under such conditions that further execution probably will not be
possible anyway). Is this a correct assumption?
 
J

Jim Langston

Erik said:
Accordin to the standard it is possible for
basic_ostream::eek:perator<<(T val), where T is a builtin arithmetic
type, to fail (and optionally throw an exception. I've been trying to
track down what would cause << to fail but have not yet been
successful, what I really want to know is whether one should bother
looking for exceptions when using code such as this to convert
arithmetic types to strings:

template<typename T>
std::string atos(const T& v)
{
std::eek:stringstream os;
if (!(os << v))
throw std::runtime_exception("Failed to convert value");
return os.str();
}

While I realise that it might be a good idea to check when converting
user defined types I hope/assume that there are no implementations out
there that would fail to convert the builtin arithmetic types (except
under such conditions that further execution probably will not be
possible anyway). Is this a correct assumption?

Consider, you are using operator<< to write to a disk file on a floppy
opened with ofstream which derives form basic_ostream (I believe). While
writing, the floppy becomes full, or someone removes it from the drive.

Or the hard drive becomes full. Or has a bad sector that gives a writing
error. Etc...

If this happens in your program, what do you want to happen? What do you
want to happen if you are writing some data to a file and the user removes
the floppy? That will tell you if you want to handle the exceptions or not.
Do you want your program to crash, or show an error box asking them to put
the floppy back in, do you want to re-write the last data attempted or the
entire file again or... if one size fit all we would't need exceptions.
 
P

Pavel Shved

Accordin to the standard it is possible for
basic_ostream::eek:perator<<(T val), where T is a builtin arithmetic
type, to fail (and optionally throw an exception. I've been trying to
track down what would cause << to fail but have not yet been
successful, what I really want to know is whether one should bother
looking for exceptions when using code such as this to convert
arithmetic types to strings...

One should. And one sould do it even in common implementations.

iostream conversions use locale abstractions to handle output complied
with national pecularities. According to standard, locale functions
may throw (much time has passed since i was trying to track it, so
you'd better research it again). And now assume that we are in the
locale of Mbongo-bongo savage tribe which has no representation of
numbers but integers from 1 to 10, or in medieval locale where 666 is
banned from being printed. The most straightforward solution here is
to throw an exception (bad_heretic, for example).

Or, to be more simple, if we're in envronment that has no IEEE-
compliant floating point aritmetical subsystem hence the
implementation doesn't know about NaNs, infinities etc and just fails
to print them.
 
J

James Kanze

Accordin to the standard it is possible for
basic_ostream::eek:perator<<(T val), where T is a builtin
arithmetic type, to fail (and optionally throw an exception.
I've been trying to track down what would cause << to fail but
have not yet been successful, what I really want to know is
whether one should bother looking for exceptions when using
code such as this to convert arithmetic types to strings:
template<typename T>
std::string atos(const T& v)
{
std::eek:stringstream os;
if (!(os << v))
throw std::runtime_exception("Failed to convert value");
return os.str();
}
While I realise that it might be a good idea to check when
converting user defined types I hope/assume that there are no
implementations out there that would fail to convert the
builtin arithmetic types (except under such conditions that
further execution probably will not be possible anyway). Is
this a correct assumption?

No.

I'm not sure that an operator<< has the right to set
failbit---the standard operator<< for basic types don't---, but
anytime the streambuf returns a failure from the attempt to
write, or throws an exception, the conversion routines should
set badbit. In the case of ostringstream, this will probably
only occur as a result of std::bad_alloc, but as Jim Langston
pointed out, with ofstream, there can be other causes as well.

Note too that with ofstream, the error might not be detected
immediately, because of buffering. You can't be sure that the
output has succeeded until after close(). And that in your
case, bad_alloc can also hit the copy constructor used to return
the value, so you have to be prepared for that anyway.
 
J

James Kanze

One should. And one sould do it even in common implementations.

Because of badbit, of course. You can't get failbit.
iostream conversions use locale abstractions to handle output complied
with national pecularities. According to standard, locale functions
may throw (much time has passed since i was trying to track it, so
you'd better research it again). And now assume that we are in the
locale of Mbongo-bongo savage tribe which has no representation of
numbers but integers from 1 to 10, or in medieval locale where 666 is
banned from being printed. The most straightforward solution here is
to throw an exception (bad_heretic, for example).

According to the standard, any function can throw anything for
any reason at all, with very few exceptions. From a quality of
implementation point of view, I would avoid implementations
which throw doubles just because it's Friday the 13th. The
standard specifies the behavior of std::num_put pretty closely,
and there's really no reason for it to throw. (A conforming
implementation cannot, for example, is required to generate
output in the specified base, and canot refused to convert 666.)
Or, to be more simple, if we're in envronment that has no IEEE-
compliant floating point aritmetical subsystem hence the
implementation doesn't know about NaNs, infinities etc and just fails
to print them.

If the environment doesn't have IEEE floating point, it can't
have infinities and NaNs to output, so the problem doesn't
arise.
 
J

Jerry Coffin

(e-mail address removed)>, (e-mail address removed)
says...
On Feb 7, 7:29 am, Pavel Shved <[email protected]> wrote:

[ ... ]
If the environment doesn't have IEEE floating point, it can't
have infinities and NaNs to output, so the problem doesn't
arise.

I suspect he's talking about a situation where the hardware is (at least
partially) IEEE-compliant, so it can produce NaNs and infinities, but
the surrounding software is not so compliant, so it doesn't know what to
do when they're encountered. Even though it's only a guess about his
situation, it's certainly a situation I've encountered in the past.

Just FWIW, there were also a number of versions of pre-IEEE floating
point that had bit patterns that corresponded (at least roughly) to
infinities, NaNs, etc. TTBOMK, the earliest was Conrad Zuse's Z1, back
in 1941 or so (it had something roughly that acted essentially the same
as a quiet NaN). The IBM stretch and CDC mainframes starting with the
CDC 6600 incorporated roughly similar ideas as well (though I'm pretty
sure there was never an implementation of C, much less C++, for any of
those).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top