3

How can I create a constructor (c++) that creates a null object when it fails.

I want to create a class that behaves like DicomImage class from the DCMTK lib.

#include "diregist.h"   /* required to support color images */
DicomImage *image = new DicomImage("test.dcm");

if (image != NULL)
{
    if (image->getStatus() == EIS_Normal)
    {
        Uint8 *pixelData = (Uint8 *)(image->getOutputData(8 /* bits per sample */));

        if (pixelData != NULL)
        {
            /* do something useful with the pixel data */
        }
    } 
    else
        cerr << "Error: cannot load DICOM image (" << DicomImage::getString(image->getStatus()) << ")" << endl;
}
delete image;
Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
garodriguezlp
  • 81
  • 1
  • 8
  • 3
    Why would anyone make `new` return null, if not on out of memory with nothrow? Why not just throw an exception, or other more proper error handling? – Max May 18 '12 at 23:39
  • 1
    Throwing an exception from a constructor is dangerous. – Gort the Robot May 19 '12 at 00:16
  • @StevenBurnap: That depends on the language and your compiler. People used to say it's dangerous with MS C++ compilers because they used to leak memory when an exception was thrown. But that's been long fixed and as long as your API is documented and callers know about exceptions, IMO, using them in the constructors shouldn't be any more dangerous than using them in normal calls. – DXM May 19 '12 at 00:47
  • consider if your constructor is `constructor() : member(new Object) {throw "Error";}` That's a leak. Now consider the same code, but where member is another class that may or may not allocate memory. It can be hard to tell in a complex constructor whether you are in this situation. – Gort the Robot May 19 '12 at 02:13
  • 2
    @StevenBurnap: Not really. Firstly, if you use `new` directly in your constructor, and `member` is not responsible for freeing `Object`, you are a moron. If `member` is responsible for freeing `Object`- then it is `member`'s job to clean up `Object` in all scenarios. You cannot have this problem if you do not violate ownership semantics. – Puppy May 19 '12 at 02:55
  • 1
    @StevenBurnap: Throwing from a constructor is the correct way to handle errors during constructor **for C++**. Your example in the next comment is bogus. It will not leak because any member that is dynamically allocated will be held in a smart pointer `std::auto_ptr member;` and thus will not leak. If you are not using smart pointers and proper RAII techniques then you are not writting C++ but rather a bastardized version of C. – Martin York May 19 '12 at 14:17

6 Answers6

2

Not easily. You could override DicomImage::operator new() inside the declaration for DicomImage class. Then the actual logic that could fail and return NULL, would go into the operator new() body, not the actual constructor. Once you are inside the constructor it's too late to return NULL, at that point the object is already created. The problem is that operator new() doesn't receive constructor parameters so you may not have information needed in order to fail.

Another way would be to have a factory method or a factory class actually create your instance, so your code would look like:

DicomImage* pImage = CreateDicomImage( "stuff" );

However because your question had "exception handling" in it... and to make, at least the answer, a little more suitable of a programmers SE (as opposed to stackoverflow) question, I do want to point out that you could and should take advantage of exception handling in C++.

When you return NULL, you force all the client code to sprinkle error checking logic right after the call to new DicomImage() which takes away from readability since error checking tends ends up intermingled with actual application logic.

Wouldn't it be better to have code that looks like:

std::unique_ptr< DicomImage > pImage( new DicomImage( "stuff" ) );
pImage->DoSomeCommand();
pImage->DoSomeOtherCommand();

... and not have to worry about "what-if" conditions if creation failed. You could achieve this by using C++ exception handling and having the constructor throw exceptions if creation fails. Setup try-catch block around the chunk of code that deals with this stuff and what goes inside that try block is pure application logic. No error checking polluting the code and no crashes if image creation fails.

...and by using the smart pointer, you also guarantee that if anything later on fails, pImage will always get deleted. So you never need to worry about having to call delete prior to exiting the function.

DXM
  • 4,413
  • 1
  • 19
  • 29
  • 2
    Just as a side note: when using exceptions you still have to worry about what happens if things go wrong - you just worry about it at a different level of the program. If you design your program correctly, you can worry about a whole lot of things in one spot, making the code overall cleaner, but it needs to be worried about somewhere. – Michael Kohne May 18 '12 at 23:45
  • @MichaelKohne: Absolutely, what Michael said :) – DXM May 18 '12 at 23:46
  • "When you return NULL, you force all the client code to sprinkle error checking logic right after the call to new DicomImage() which takes away from readability since error checking tends ends up intermingled with actual application logic.": If you use a factory method and consider the return type as an optional type (e.g. in Haskell pseudocode: Maybe DicomImage) then NULL corresponds to the return value Nothing, and checking it would be part of the normal application logic. IMO it depends on whether you interpret NULL as an error or as an empty result. – Giorgio May 19 '12 at 06:38
1

The code that uses DicomImage doesn't do what you think it does.

The example code

if (image != NULL)
{

is defensive programming for an exception-less environment that returns NULL when the system is out of memory.

With exceptions enabled, new will throw an out of memory exception. If exceptions are disabled, then new will return NULL.

To answer your question, a constructor cannot return NULL.

However, a static factory method can return NULL.

class Foo
{
public:
    static Foo* MakeFoo()
    {
       Foo* foo = NULL;
       if (LifeIsGood())
           foo = new Foo();
       return foo;
    }
private:
    Foo();
};

Foo* myFoo = Foo::MakeFoo();
if (myFoo)
    BeFooish(myFoo);
Bill Door
  • 18,272
  • 3
  • 32
  • 37
0

I don't think a constructor can do this - this url says a constructor can't return null

http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/1450ed84-277f-46d3-b2ea-8352986f877c

Maybe there is a "hack" but it is probably not legal You probably already know all of this but just in case: (1) A constructor can't return a value, and (2) I don't think it has any control over the memory allocated to the instance that invoked the constructor, but a constructor can set class members to NULL values.

This URL has a workaround - if you really need to use NULL (not recommended) making the constructor private and using a "factory method" (function):

Can a constructor return a NULL value?

I know this is separate from your question but I just wanted to make sure someone is aware of the compiler behavor with regards to new:

According to this URL, up-to-date compilers are not supposed to return NULL with the new operator (are supposed to throw an exception instead), although older compilers are allowed to do it:

http://www.parashift.com/c++-faq-lite/new/new-never-returns-null.html

Community
  • 1
  • 1
A B
  • 4,068
  • 1
  • 20
  • 23
  • As usual the notes from parashift are not all accurate (not a good site to quote from the site is sprinkled with incorrect information and just plain bad examples but they are hard to spot because they are mixed with good examples and correct information). Lets just say that **under normal usage** throw will **never return NULL** (unless you are it to). The people using non standard compilers already know their compilers weaknesses and explaining this information detracts from the message you are trying to explain. – Martin York May 19 '12 at 14:27
0

You can't, and judging by the documentation of DicomImage, you really don't want to emulate that class's interface.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

Doing this using the new() operator is not really the purpose for which overriding the new() operator was intended. From your example, I'm not sure if you are allowing changing the client code; however if you can control the client code, instead just use a factory method where you would use a constructor:

class Foo {

  Foo(int arg) {...}

  static Foo *new_Foo(int arg) {
    if (! I_like(arg)) return null;
    return new Foo(arg);
  }

}

// ...
// in the client

Foo *foo =
// nope:
// new Foo(3);
// do this instead:
Foo.new_Foo(3);
Daniel
  • 1,861
  • 1
  • 16
  • 24
  • 1
    IF you do this then new_Foo() should be a static member. Also its what is considered a factory method (see gang of four). Try and identify it as a factory method with your naming convention. – Martin York May 19 '12 at 14:21
  • Then you are missing the main lesson from the GoF. http://programmers.stackexchange.com/a/70893/12917 The power of design patterns is in communication. If you leave out things like the purposes you make people try and understand your code. Mainly because your function is not just newing an object it is doing other tasks as well. Thus 'FooBuilder()` of 'FooFactory()` are definitely more appropriate and help the maintainer much more than `new_Foo()` especially since that is not what is doing (just part of it). – Martin York May 19 '12 at 19:39
  • I disagree that GoF are the ultimate authority. I disagree that the power of design is in communication; the power of design is in making use of a semantic symmetry to get mechanic symmetry. – Daniel May 19 '12 at 23:40
  • They are not the ultimate authority. That is why I provided an alternative link so you can do more reading. – Martin York May 20 '12 at 00:46
0

You can not return null in an object creation, however you can change the behavior of operator == and!= Try the following code, I have not tried.

bool MyClass::operator==(const MyClass &other) const {
    if(&other == null){
        if(/* your validations */){
            return true;//it is null
        }else{
            return false;//
        }       
    }
    return (*this == other);//it is not compare with null
}
bool MyClass::operator!=(const MyClass &other) const {
    if(&other == null){
        if(/* your validations*/){
            return true;//is not null
        }else{
            return false;
        }       
    }
    return !(*this == other);//it is not compare with null
}
Jose Nobile
  • 3,243
  • 4
  • 23
  • 30