Re: Throwing exception in constructor
Alf P. Steinbach wrote:
According to my research so far, its OK to
throw an exception in a constructor, only thing is that
destructor for that class wont be called,
Almost right. It's not just OK to throw an exception to
signal a construction failure. In not-extremely-badly
designed code it's mandatory, to ensure you only ever deal
with fully initialized objects, and no half-way constructed
objects (doing the opposite is one way of streching a 2 to 3
hour programming job into 2 or 3 weeks...).
That's generally the rule. But there are exceptions, and I
wouldn't consider the iostream hierarchy poorly designed because
ifstream doesn't throw if it cannot open the file.
Right -- the effects of the poor design shows up in other ways... ;-)
object can become invalid during its lifetime (and so later
tests of validity or success are necessary anyway), the argument
based on the absense of invalid objects looses its power.
Just a little. Mostly the argument is against an additional nullstate
(zombie state) /mixed in with other state/, which must be checked
everywhere, leading to complexity (a.k.a. spaghetti) and bugs. As an
example, and this is a special case of a well-known state pattern I
forget the name of, access of an object representing an open file can be
restricted to a special kind of smart-pointer so that the "real" object
doesn't need to deal with the nullstate, except notifying the containing
smart pointer of its further non-existence, and so that the containing
smart pointer only deals with (throwing exceptions on operations on)
nullstate: clean code in both classes, and reusable generic nullstate.
Why isn't it ordinarily done that way?
Well, why am I currently fighting with triple-phase initialization and
other monstrosities? I think there's a very strong tendency to design
and code /locally/ for what the slightly less than average programmer in
the firm/shop/project can be expected to understand and maintain. Then
this seemingly bright idea yields unmaintainable global spaghetti, which
in turn yields local spaghetti, 99.7% contrary to what one aimed for.
(Depending on the case, there may be other arguments for
exceptions in such cases. But it's not the cut and dried case
it would be otherwise.)
There are also probably a few rare cases (although I can't think
of any off hand) where it is justified to use a factory
function, which either separates initialization from
construction, or tests the success of the constructor, and in
case of failure, deletes the object and returns a null pointer.
Ah, you're thinking of deserialization... ;-)
At least, I've been thinking about it lately.
There is a conflict there between the initialization order imposed by
C++ and the order very strongly suggested by the serialized data. One
solution is buffering, another and probably both more practical and
efficient solution is to cast the data member declaration order in stone
for serializable objects, and a third is to not regard the serialized
data as a stream, but as random access. Whatever solution one adopts
(and mostly it seems serialization frameworks, including the one in
Boost, choose none of these reasonable options and instead go for ugly
two-phase initialization) there is some trade-off: that's engineering.
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]