views:

676

answers:

12

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.

+13  A: 

Constructors 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.

David Rodríguez - dribeas
+1 very good points!
FredOverflow
While it's not always a great idea, it's also possible for a failed constructor to leave the instance in a well-defined invalid state that can be tested for later. My answer includes an example of this. Having said that, I do favor just throwing in the constructor.
Steven Sudit
+7  A: 

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++.

AraK
+1 - If the constructor fails, it should *fail* -- with an exception.
T.J. Crowder
+6  A: 

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.

Mark
There are two flavors of new, the regular will throw, but you can use the nothrow version that will return a null pointer if it fails to allocate memory. Again, the answer is correct because the choice of returning a null pointer is only available for memory allocation failures *before* calling the constructor.
David Rodríguez - dribeas
A: 

You shouldn't perform such work in a constructor. Constructors should perform the absolute minimum amount of work to make an object usable.

DeadMG
Complete and utter nonsense.
anon
A constructor is used to build the object. If the object cannot be built the constructor has to handle it. You can argue that it should throw an exception (as the other answers say), but still this HAS to be done in the constructor.
nico
+1 I have to agree with this post. This constructor has too many responsibilities. It's opening a file, reading a file, verifying the file, and building an object out of the result. What the OP needs is to separate these responsibilities so that the reading and verification is done in a separate object and the result of that operation can then be used to build CMyClass. This answer could have been more informative/verbose but it certainly does not deserve as many negs as it has.
Noah Roberts
Noah - this is exactly wrong - if you call a constructor it wil return you the CMyClass if and only if it managed to load and validate the file - you do not have to see the case where the file is invalid or missing etc. Now the CMyClass constructor can use several classes to achieve this but to the user it either works or does not.
Mark
@Noah Roberts: What constructor are you talking about? I don't see a particular one in this question. I will agree that it's possible for a constructor to do too many things, but I'd have to look at it to decide for myself. As far as the answer goes, it's an opinion, backed up by nothing, that is not held by any C++ expert I know of, on or off SO. It is, therefore, worthless, unless edited to include some sort of argument.
David Thornley
@thornley - the constructor I'm talking about is the one described by the OP: " 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"
Noah Roberts
@Mark - you've said nothing that invalidates my point, you've just re described the poorly design constructor in question. A constructor is meant to build an object, not to check if it's possible to build that object nor gather the resources to do so. One simple way of pointing this out would be to ask how one would change the method of gathering the images to build CMyClass. If CMyClass wasn't taking it upon itself to "do it all" it would be a simple matter of changing how one derived the set of images passed to its constructor. CMyClass would not require surgery.
Noah Roberts
@Noah: Read up on http://en.wikipedia.org/wiki/RAII, then post a humble retraction.
Steven Sudit
@Steven - don't know what you think that's supposed to say in regard to what I've said. RAII can certainly be used with a design that separates concerns and does not require that an object which uses a thing to also find, check the availability of, and build that thing.
Noah Roberts
In order to shore up where people are coming from: If `Image` has a constructor that accepts an input stream and uses data from that stream to build an image, throwing an exception if the stream is invalid, is that too much responsibility? If `Model` has a similar constructor, but it builds several `Image` objects, and then pieces them together into a larger image, is that too much responsibility?
Dennis Zickefoose
@Noah: Seriously, read the article. It explains why you want the constructor to build an object *and* to throw an exception if it cannot. Dennis' example is also valid.
Steven Sudit
Rather than complain about how wrong your answer is, I've added my own.
Steven Sudit
@steven - that article does not say what you think it does. As I already stated, an object that's only purpose is to process files can be expected to do so. That is what the class in the article is doing. They are not explaining why you would want to create a complex constructor with multiple responsibilities and multiple points of failure.
Noah Roberts
@Noah: Reading an image file and decoding it does not amount to "multiple responsibilities".
Steven Sudit
@Dennis - Pretty much. Why is Model insisting on a particular method of getting a list of images? Model should leave such things to the client. Otherwise the constructor of Model is not building a Model, it's doing a whole list of things and THEN building a Model iff it succeeded in those things.
Noah Roberts
@Steven - you seem to be confused. First of all there are many more responsibilities in the OP's description of their constructor. Second of all, two responsibilities is "multiple" or is it not? If "and" is in the sentence that describes what a function does then it is doing more than one thing.
Noah Roberts
@Steven: Sure it does. It corresponds to two responsibilities, and you can tack on "represents an image" as a third one.
Dennis Zickefoose
@Dennis: And by that argument, the string constructor from const char* combines strlen, strcpy and memory allocation. :-) The question isn't whether we can break the task down into subtasks but whether they come together into a logically cohesive task that is consistent with the requirements of creating the object.
Steven Sudit
@Steven - you also seem to think that I've said one should not throw or relay exceptions if construction fails. That is actually a perfectly valid use of exceptions. I'm simply stating that a constructor that does too much is a poor design and that DreadMG was right about the fact that this one is described such.
Noah Roberts
@Noah: It's not poor design for an image constructor to load an image. See http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.bitmap(v=VS.100).aspx
Steven Sudit
@Steven - that's of course debatable and beside the point of the conversation since this is not what the OP claimed their constructor does. Furthermore, I haven't really come to the conclusion that microsoft libraries and products represent best design practices. In my opinion an Image would be a generic construct capable of representing any Image type and processing from a file format to that internal representation would be done by something else entirely. Such would be a better design that having the Image representation also responsible for decoding image file formats.
Noah Roberts
@Noah: If you read the link, you'll find that Bitmap inherits from Image, which is indeed a "generic construct construct capable of representing any Image type". While it is possible to separate the file support from the image in memory, I don't see how this is an improvement.
Steven Sudit
@Steven - Whether or not it is reasonable really depends on what, if anything, Save() is doing. At any rate, arguing this red herring with you is getting beyond pointless. The OP has described a constructor that does a whole lot more than load AN image from A file. As to your former comment, in general I prefer composition over inheritance. I'm standing in great company with that opinion. Inheriting Bitmap from Image does, indeed, smell to me but in order to see if it is "bad" would require further research. Maybe it was necessary; maybe MS did something stupid.
Noah Roberts
@Noah: I accept your concession.
Steven Sudit
@Steven - Intellectual dishonesty seems to suit you quite well. HEHEHE just checked your profile. Should have realized I was arguing with a child.
Noah Roberts
@Noah: Look, you can either support your claim or retract it. Failure to do the former is equivalent to the latter. Unfortunately, you cannot support your claim, so you resort to insult. The world is full of counterexamples against your claim, so you should have taken my advice by simply admitting that you're wrong instead of sinking this low.
Steven Sudit
I did just fine with supporting my claim. I'm quite sure the world IS full of counterexamples but first off, you don't seem to understand my claim well enough to find one, and second off, it's completely beside the point. No, I am not going to continue; claim "victory" if it makes you feel better but it won't make you any more correct.
Noah Roberts
+13  A: 

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

Michael Mrozek
Thanks. I was thinking of that myself but I didn't really try it in C++ till now. I might not be able to allocate them on the stack memory but frankly I have need for that and thus this should be best approach.
Sanctus2099
@Sanctus How is your constructor supposed to "return null" with stack instances?
FredOverflow
@Fred He meant he has no need for it, I assume
Michael Mrozek
Yes I did but for some reason I can't edit my comment.
Sanctus2099
@Sanc You can only edit comments for the first five minutes after posting
Michael Mrozek
This is the right answer to the wrong question: he ought not be trying for this.
Steven Sudit
@Steven Possibly, but I hate when people refuse to answer a question because they think the poster is doing the wrong thing; it's entirely possible he (or some future reader looking for the answer to this question) has a legitimate need that would take too long to explain to us
Michael Mrozek
@Michael: And I appreciate that you did try to answer the question, but I think we have a responsibility to *also* tell people when their question is broken. That's why I don't pretend that my answer should have been accepted or yours deserves a downvote.
Steven Sudit
+2  A: 

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.

uosɐſ
A: 

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.

Pete Kirkham
This was standard C++ at the time VC6 was written.
Joshua
@Joshua: That was never standard C++ in the sense of an official standard, which didn't exist when Visual C++ 6 was written. It may have been in accordance with the Annotated Reference Manual, which was the base document for the C++ standard, but I don't have a copy of that.
David Thornley
FYI, going backwards through the history of C++, new predates exceptions.
Joshua
+1  A: 

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.

Joshua
That's a rather sneaky approach but could be very usefull. I think I'll test it a bit.
Sanctus2099
@Sanctus: Don't do this. Its a horrible idea. Nobody expects `new` to ever return `0` unless they explicitly asked for the `nothrow` version. `p = new Blah; if(p) ...` is a sign of somebody who doesn't know what they're doing.
Dennis Zickefoose
I'm sorry but your post doesn't really give any good arguments. I'll probably end up using factories but it's a fun test.
Sanctus2099
@Sanctus: I assume you mean me? If so, the principle of least surprise is *always* a good argument. Code it once as an exercise in overloading `operator new` if you want the experience, but then throw the code away and never do it again.
Dennis Zickefoose
A: 

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).

Noah Roberts
A constructor should do whatever is needed to create the object, even if this involves considerable processing. Consider Dennis' example of an Image class that reads a file and decodes a compressed image.
Steven Sudit
Ergo the correct way to build that Image example is to pass a string of characters that the constructor can then use to look for a file on the filesystem, open it, process it, and explode if any of that fails. I stand corrected....I guess. Yes, I'm being sarcastic. That's just stupid, isn't it. Constructors should, generally speaking, have empty bodies.
Noah Roberts
@Noah: This is your claim, but it is entirely unsupported, and easily refuted.
Steven Sudit
A: 

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.

Thomas Matthews
This is a bad idea, because even if you use placement new to instantiate the object in the memory you just allocated, cleaning up the object becomes a mess: you'll need explicit destruction and then a call to free. And it still doesn't solve anything because the constructor itself can throw.
Steven Sudit
Plus if you only want to avoid the `new` part from throwing, you can use `new (nothrow)`...
David Rodríguez - dribeas
Look, I know the standard allows for new to not call malloc to get its memory, but it wasn't a very bright idea for the standard library (non-overloaded) version to bypass malloc.
Joshua
Yes, I know it is a bad idea, but it meets the OP's requirement for returning NULL from constructing an object.
Thomas Matthews
+1  A: 

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.

Steven Sudit
Considering you've made such a big deal about RAII, providing an answer that doesn't make use of it seems rather peculiar.
Dennis Zickefoose
Point taken, but I'm not dogmatic. The above class *allows* for RAII and even encourages it, but it also gives you an alternative. Even when initialization is delayed, it still has a destructor that cleans up the resources, so it accomplishes the primary goal of RAII: avoiding leaks. Still, in response to your comment, I'll add another constructor, which allows exception suppression.
Steven Sudit
@Dennis: To clarify, the non-throwing constructor allows for RAII but optionally replaces exceptions as the indicator of a failed construction with with a validity flag. Whether it makes Load redundant is an open issue. Again, I'm not dogmatic; I really care whether the code leaks, though.
Steven Sudit
A: 

Exceptions are ur best bet. You could also check the value of errno if youre programing in unix environment.

Ram Bhat