I know constructors don't "return" anything but for instance if I call CMyClass *object = new CMyClass()
is there any way to make object to be NULL if the constructor fails? In my case I have some images that have to be loaded and if the file reading fails I'd like it to return null. Is there any way to do that?
Thanks in advance.
views:
676answers:
12Constructors do not return values. They initialize an object and the only way of reporting errors is through an exception.
Note that the constructor does not make any type of memory management. Memory is allocated externally and then the constructor is called to initialize it. And that memory can be dynamically allocated (type *x = new type;
) but it might as well be in the stack (type x;
) or a subobject of a more complex type. In all but the first case, null does not make sense at all.
The "correct"** way is to throw an exception.
** You can provide a member function like is_valid
that you can check after constructing an object but that's just not idiomatic in C++.
The way to do this is if you find something not working in your constructor you should throw an exception. This is what happens if C++ cannot allocate memory for your object - it throws std::bad_alloc. You should use std::exception or a subclass.
You shouldn't perform such work in a constructor. Constructors should perform the absolute minimum amount of work to make an object usable.
I agree with everyone else that you should use exceptions, but if you do really need to use NULL for some reason, make the constructor private and use a factory method:
static CMyClass* CMyClass::create();
This means you can't construct instances normally though, and you can't allocate them on the stack anymore, which is a pretty big downside
Could use a static factory method instead? When converting between types, I might make a public static CMyClass Convert(original) and return null if original is null. You'd probably still want to throw exceptions for invalid data though.
In Visual C++ 6, the default behaviour on memory starvation was for the new operator to return NULL rather than throw an exception. This was neither standard C++, nor idiomatic. But you certainly can create a version of operator new which behaves in that manner if you so wish.
In bad taste.
Well if you actually want to do this, overload new, have new call a private constructor that does no initialization, do the initialization in new, and have new return null if initialization fails.
You can actually cause new to "return" 0 by using std::nothrow but this only causes it to return 0 if the memory allocation fails. Once it's gotten to your constructor there's no way to get what you want.
You should separate the concerns in your class. A constructor should almost never (I am tempted to say 'never' period but I'll leave room for the rare exception I can't think of) do file processing unless file processing is its sole responsibility (such as fstream).
You could use malloc
instead of new
since malloc
does not throw exceptions. You will have to test the result of malloc
before you use the pointer. Also, if malloc
succeeds, you will have to initialize the object.
Warning:
malloc
does not call the object's constructor.
Rather than telling you how to get a constructor to return null, or how to fake it, let me suggest an alternative: offer a way to avoid throwing an exception, such as by delayed initialization or a non-throwing constructor. Once you do this, though, you need to have a way to check validity and to ensure that any attempt to use an invalid instance does throw an exception. In other words, you're delaying the exception, not avoiding it entirely.
Here's how: You already have a constructor that takes a file path and loads it, throwing on failure. Move the guts into a Load method that takes the file path and returns a bool to indicate success. Then change the constructor so it simply calls Load and throws on false. In Load, make sure to immediately return false if the instance is properly initialized. Then add a default destructor and an IsValid method.
Per Dennis: Now add a second constructor that takes a boolean to control whether an exception is thrown, and consider relegating Load to private, in which case you would likewise remove the default constructor.
This gives you all that you can ask for, without making unmaintainable code. It should look something like this:
// Per Dennis, should go away if Load becomes private.
Image()
{
_valid = false;
}
Image(const string& filepath)
{
if (!Load(filepath))
throw new exception("Cannot open image.");
}
// Per Dennis.
Image(const string& filepath, bool doThrow)
{
if (!Load(filepath) && doThrow)
throw new exception("Cannot open image.");
}
// Per Dennis, this should probably be made private now.
bool Load(const string& filepath)
{
if (_valid)
return false;
// Try to load...
_valid = WhetherItLoadedExpression;
return _valid;
}
bool IsValid()
{
return _valid;
}
void Draw()
{
if (!IsValid())
throw new exception("Invalid object.");
// Draw...
}
edit
See below for changes made in response to Dennis' comment.
Exceptions are ur best bet. You could also check the value of errno if youre programing in unix environment.