Constructor denial?

  • Thread starter Thread starter Peter Oliphant
  • Start date Start date
P

Peter Oliphant

Is it possible to have a constructor REFUSE to be constructed? That is, can
one within a constructor check to see if I really want to be constructed,
and return a nullptr instead of a valid object address when a construction
is attempted? Note that 'in the old days', a call to malloc( ) would return
'null' if it couldn't make the allocation for some reason. I'm wondering if
this capability has been preserved in 'gcnew'?

Immediately I can see why this wouldn't be possible if you allow stack
semantics. But I also have noticed that I can't create arrays in stack
semantics (the elements can be objects, but the array must be instantiated
as a pointer). Thus, such restrictions, not allowing stack semantics for
some cases, is not without its precedence...

Not really anything to do with my projects, just a thought that came to
mind...

[==P==]
 
there are 2 things you can do:
- throw an exception, but then you'll have to catch it.
- create a custom 'new' operator that returns NULL if it determines that
your constructor failed. you'd have to make some mechanism to let your new
operator know that the constructor failed, but that would work i think.

kind regards,
Bruno.
 
Yes, I can see how exception processing could be used, but this requires
putting all construction attempts of the class in a try/catch block (at some
level).

Therefore this isn't a 'solution' to what I asked about. That is, having a
constructor just return 'nullptr' to deny construction. Note that 'malloc'
returns a 'null' and requires no exception processing *on the part of the
caller*.

Now, one way is to wrap the constructor in another class that attempts the
construction and returns a nullptr if the exception fires, or a pointer to
the newly constructed instance of original class if successful (a 'factory',
if you will). And such a method could be made static. That would work, but
is cumbersome.

I'm guessing it's not possible to actually just return 'nullptr' in a
construction attempt like 'malloc' does...

[==P==]
 
Peter said:
I'm guessing it's not possible to actually just return 'nullptr' in a
construction attempt like 'malloc' does...

You can add a static member to the class, and call that instead of the
constructor. It doesn't require a separate factory class. You can
optionally make the constructor private, if you want to force your own
function instead.

class C
{
public:
C();
static C* TryCreate()
{
try
{
C* c = new C;
return c;
}
catch(...)
{
return 0;
}
}
};

You can apply the same idea to C++/CLI. It's not that cumbersome, but I
don't see why you prefer nullptr to an exception. If construction fails,
that's almost always an error, and therefore the exception is valid.

Optionally, you can set a failed flag in the constructor, and add a bool
IsValid() const member function. It's very good for classes that can
fail for a valid reason, which as a FileStream.

Tom
 
Peter said:
Yes, I can see how exception processing could be used, but this requires
putting all construction attempts of the class in a try/catch block (at some
level).

yes, but trick with using exceptions *correctly* is to have very few of
these try/catch blocks. Thus you won't use such a block to handle single
failed construction; instead you will put it where it does make most
sense to present all errors to the user or otherwise *sensible* recover
from error condition (without gimmics to pretend that everything is
under control, when in fact it is not, in this particular part of code).
I encourage you to read Herb Sutter's "Exceptional C++" series of books
to understand more of this. These books are pretty good read, actually
(especially first and third one, at least to me)


B.
 
Or you can supply your own 'new' operator for that class. in that case you
can use a flag or an exception in your constructor to signal that
construction has failed, and let the 'new' operator return a NULL pointer.

kind regards,
Bruno.
 
Bruno said:
Or you can supply your own 'new' operator for that class. in that case you
can use a flag or an exception in your constructor to signal that
construction has failed, and let the 'new' operator return a NULL pointer.

nothrow variant of new operator must not return null, while throw
variant must be explicitly called and always checked for null, which is
at least cumbersome. Futhermore, operator new does not have access to
constructor parameters.

If you want object construction to fail, just throw an exception during
construction. If you do not want exceptions (eg. due to performance
reasons), use factory or static function and create object on heap,
allowing null pointer to be returned when object cannot be created - but
be aware that heap allocations are much more expensive than creating
object on stack. See also http://www.gotw.ca/gotw/066.htm


B.
 
Peter said:
Yes, I can see how exception processing could be used, but this
requires putting all construction attempts of the class in a
try/catch block (at some level).

Therefore this isn't a 'solution' to what I asked about. That is,
having a constructor just return 'nullptr' to deny construction. Note
that 'malloc' returns a 'null' and requires no exception processing
*on the part of the caller*.

Returning a "nullptr" requires the caller to check for luillity (because
dereferencing a nll pointer is invalid of course). So whatever method you
use (exception or anything else), if a constuctor can "fail", the caller
that want to construct an object *must* check wether the creation failed or
not. Only the syntaxic form of the check changes, not it's necessity.

Btw, if used correctly, exceptions allow to have only a few error checks
(catch clauses), at least less than the "if"s necessary to check errors in
C.

Arnaud
MVP - VC
 
Bronek said:
nothrow variant of new operator must not return null, while throw
variant must be explicitly called and always checked for null, which is
at least cumbersome. Futhermore, operator new does not have access to
constructor parameters.

I think you have that the wrong way. The new variant that does not
throw MAY return a NULL pointer to indicate failure, whereas the new
that throws must not, instead resulting in an exception being thrown.

-n
 
Nikolaos said:
I think you have that the wrong way. The new variant that does not
throw MAY return a NULL pointer to indicate failure, whereas the new
that throws must not, instead resulting in an exception being thrown.

this is what I meant; sorry for confussion.


B.
 
Back
Top