31

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.

Sanctus2099
  • 1,669
  • 5
  • 22
  • 40
  • A problem is that I don't want to create exceptions. – Sanctus2099 May 18 '10 at 16:35
  • You can provide a function that validates that object, just like in `fstream` where you call `is_open()` to check if things went correctly before you proceed. – Khaled Alshaya May 18 '10 at 16:37
  • 16
    Why do you want to avoid exceptions? They're a pretty basic part of C++. – David Thornley May 18 '10 at 16:39
  • 1
    @DavidThornley There's a certain "visual cost" to the code you chose to write. `try/catch` blocks are no "exception". If the code interacts with a lot of C-like code, a `try`/`catch` block can look out of place. You have `O*o=O::createO() ; if( !o ) { /*handle*/ }`, which looks very C-like, vs `O*o;try{o=new O();}catch(...){/*handle*/}`. My point is these look totally different, and I think the choice _not_ to use exceptions can really be a stylistic one. But you know, half a dozen of one thing, 6 of another. – bobobobo Jul 13 '12 at 19:12

15 Answers15

29

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.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • 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 May 18 '10 at 16:38
  • 3
    @Sanctus How is your constructor supposed to "return null" with stack instances? – fredoverflow May 18 '10 at 17:29
  • 1
    @Fred He meant he has no need for it, I assume – Michael Mrozek May 18 '10 at 18:29
  • @Sanc You can only edit comments for the first five minutes after posting – Michael Mrozek May 18 '10 at 18:45
  • 1
    This is the right answer to the wrong question: he ought not be trying for this. – Steven Sudit May 18 '10 at 19:52
  • 13
    @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 May 18 '10 at 20:34
  • 3
    @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 May 18 '10 at 21:18
24

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
  • 204,818
  • 23
  • 294
  • 489
  • 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 May 18 '10 at 22:11
10

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

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
6

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.

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
  • 4
    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 May 18 '10 at 16:27
3

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.

Jason Kleban
  • 20,024
  • 18
  • 75
  • 125
2

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
  • 19,391
  • 1
  • 51
  • 53
  • 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 May 18 '10 at 19:59
  • 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 May 18 '10 at 20:08
  • @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 May 18 '10 at 20:16
1

This can be done a little hackish by overriding the new operator

See this example:

http://coliru.stacked-crooked.com/a/62e097827724f91e

Technically it's no longer a constructor but it does behave the way you want it.

JDel
  • 61
  • 8
1

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 not the behaviour later standardised in C++, nor idiomatic in modern C++.

But you certainly can create a version of operator new which behaves in that manner if you so wish, or use the nothrow variant : if ( Foo * foo = new ( std::nothrow ) Foo ) { ... }.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • This was standard C++ at the time VC6 was written. – Joshua May 18 '10 at 16:28
  • @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 May 18 '10 at 16:37
  • FYI, going backwards through the history of C++, new predates exceptions. – Joshua May 18 '10 at 23:20
1

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
  • 40,822
  • 8
  • 72
  • 132
  • That's a rather sneaky approach but could be very usefull. I think I'll test it a bit. – Sanctus2099 May 18 '10 at 16:48
  • 4
    @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 May 18 '10 at 17:34
  • 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 May 18 '10 at 18:42
  • 4
    @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 May 18 '10 at 18:57
1

Present message should be a comment on the answer, but there is not a good place to see code!

I've stumbled across the following code:

std::ofstream f(m_filename);
if (!f)
     return false;

and saw it actually passing on the return false; statement. And said "What? Did the constructor return NULL?"

I was being mislead, as the if makes an implicit call to the operator bool() of the ofstream class.

sergiol
  • 4,122
  • 4
  • 47
  • 81
1

if I call CMyClass* object = new CMyClass() is there any way to make object to be NULL if the constructor fails?

I see what you mean! There are lots of C++ libraries out there that make heavy use of dynamically allocated memory and implement this idea (such as QtGstreamer), so its definitely possible to write your code to look like:

CMyClass* object = new CMyClass()
if (!object)
{
    // FAILED!
}

However, its not the constructor of the object that returns NULL. It's an overloaded version of operator new.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
0

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

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • 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 May 18 '10 at 19:33
  • 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. – Edward Strange May 18 '10 at 20:02
  • This is your claim, but it is entirely unsupported, and easily refuted. – Steven Sudit May 18 '10 at 21:12
0

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
  • 56,849
  • 17
  • 98
  • 154
  • 2
    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 May 18 '10 at 19:31
  • 1
    Plus if you only want to avoid the `new` part from throwing, you can use `new (nothrow)`... – David Rodríguez - dribeas May 18 '10 at 23:19
  • 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 May 18 '10 at 23:21
  • Yes, I know it is a bad idea, but it meets the OP's requirement for returning NULL from constructing an object. – Thomas Matthews May 19 '10 at 16:06
0

Exceptions are your best bet.

You could also check the value of errno if you're programming in a Unix environment.

mwfearnley
  • 3,303
  • 2
  • 34
  • 35
Laz
  • 6,036
  • 10
  • 41
  • 54
-2

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

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 8
    Complete and utter nonsense. –  May 18 '10 at 16:21
  • 1
    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 May 18 '10 at 16:23
  • 1
    +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. – Edward Strange May 18 '10 at 16:28
  • 4
    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. – mmmmmm May 18 '10 at 16:38
  • 6
    @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 May 18 '10 at 16:55
  • @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" – Edward Strange May 18 '10 at 17:20
  • 2
    @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. – Edward Strange May 18 '10 at 17:21
  • @Noah: Read up on http://en.wikipedia.org/wiki/RAII, then post a humble retraction. – Steven Sudit May 18 '10 at 17:45
  • @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. – Edward Strange May 18 '10 at 17:59
  • 2
    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 May 18 '10 at 19:02
  • @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 May 18 '10 at 19:28
  • Rather than complain about how wrong your answer is, I've added my own. – Steven Sudit May 18 '10 at 19:53
  • @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. – Edward Strange May 18 '10 at 20:04
  • @Noah: Reading an image file and decoding it does not amount to "multiple responsibilities". – Steven Sudit May 18 '10 at 20:05
  • @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. – Edward Strange May 18 '10 at 20:09
  • @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. – Edward Strange May 18 '10 at 20:11
  • @Steven: Sure it does. It corresponds to two responsibilities, and you can tack on "represents an image" as a third one. – Dennis Zickefoose May 18 '10 at 20:12
  • @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 May 18 '10 at 20:19
  • @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. – Edward Strange May 18 '10 at 20:20
  • @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 May 18 '10 at 20:26
  • @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. – Edward Strange May 18 '10 at 20:34
  • @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 May 18 '10 at 20:42
  • @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. – Edward Strange May 18 '10 at 20:59
  • @Steven - Intellectual dishonesty seems to suit you quite well. HEHEHE just checked your profile. Should have realized I was arguing with a child. – Edward Strange May 18 '10 at 21:51
  • @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 May 18 '10 at 21:52
  • 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. – Edward Strange May 18 '10 at 22:18