CodingLab
CodingLab

Reputation: 1519

How can I check the failure in constructor() without using exceptions?

All of the classes that I'm working on have Create()/Destroy() ( or Initialize()/Finalized() ) methods.

The return value of the Create() method is bool like below.

bool MyClass::Create(...);

So I can check whether initialization of the instance is successful or not from the return value.

Without Create()/Destroy() I can do the same job in constructor() and destructor() but I can't solve below problem.

Can anyone help me? Thanks in advance.

I cannot use exceptions because my company doesn't like it.

class Foo
{
private:
    AnotherClass a;
public:
    Foo()
    {
        if(a.Initialize() == false)
        {
            //???
            //Can I notify the failure to the user of this class without using exception?
        }
    }
    ...
};

Foo obj;

Upvotes: 7

Views: 9291

Answers (10)

Jorge Bellon
Jorge Bellon

Reputation: 3106

I also came across this problem. I think an elegant solution is making the real constructor private, and then use a factory to return an instance and the error.

I'm not keen on retrieving an error via output argument, so I'd put both success and possible instance in a struct:

template < class T >
struct expect {
   expect( T v ) :
      failure(false),
      value(v) // or std::move(v)
   {
   }

   expect( int e ) :
      failure(true),
      error(e)
   {
   }

   bool failure;
   union {
      T value;
      int error;
   };
};

class A {
   public:
      expect<A> create( /* arguments */ ) {
         if( /* check fails */ ) {
            return expect(error_code);
         }
         return expect( A(/*arguments*/) );
      }
   private:
      A( /* constructor that does not fail */ );
};

This is a popular pattern that is being proposed as an extension to the standard. The advantage is that your code can still use RAII with this.

I recommend to watch Andrei Alexandrescu's talk on systematic error handling in C++.

Edit: It is 2023 and this is now part of C++23 standard! 🎉 See: https://en.cppreference.com/w/cpp/utility/expected

Here's an example with UNIX's open/close interface (I'm not sure the std::error_code part is correct).

class A {
public:
    using A_or_error = std::expected<A, std::error_code>;

    static A_or_error create(const char *path) {
        int fd = open(path, O_RDONLY);
        if (fd == -1)
            return A_or_error(std::unexpect, errno, std::system_category());
        return A_or_error(A(fd));
    }
    
    ~A() { close(fd); }

private:
    A(int fd) : fd(fd) {}

    int fd;
};

https://godbolt.org/z/7xnG6jY7e

Upvotes: 5

paxi
paxi

Reputation: 31

it is safe to avoid having code that causes failures within constructor or descructor. Have one more member say, bool Initialize(), bool Uninitialize() to have those kind of codes.

Upvotes: 3

user403203
user403203

Reputation:

I've tried all alternatives to exceptions I could find (member error variable, even setjmp/longjmp), and they all sucked in their own special way. A very uncommon pattern which I've come to love is passing a reference to an error object around, and checking if an error is pending as the very first operation in any function:

int function1(Error& e, char * arg)
{
    if(e.failure())
        return -1; // a legal, but invalid value

    // ...
}

int function2(Error& e, int arg)
{
    if(e.failure())
        return -1; // a legal, but invalid value

    // ...
}

int function3(Error& e, char * arg)
{
    if(e.failure())
        return -1;

    // if function1 fails:
    //  * function2 will ignore the invalid value returned
    //  * the error will cascade, making function2 "fail" as well
    //  * the error will cascade, making function3 "fail" as well
    return function2(e, function1(e, arg));
}

With some work, it applies to constructors as well:

class Base1
{
protected:
    Base1(Error& e)
    {
        if(e.failure())
            return;

        // ...
    }

// ...
};

class Base2
{
protected:
    Base2(Error& e)
    {
        if(e.failure())
            return;

        // ...
    }

// ...
};

class Derived: public Base1, public Base2
{
public:
    Derived(Error& e): Base1(e), Base2(e)
    {
        if(e.failure())
            return;

        ...
    }
};

The main issue is you don't get automatic deletion in case the constructor of a dynamically allocated object fails. I typically wrap invocations of new in a function like this:

// yes, of course we need to wrap operator new too
void * operator new(Error& e, size_t n)
{
    if(e.failure())
        return NULL;

    void * p = ::operator new(n, std::nothrow_t());

    if(p == NULL)
        /* set e to "out of memory" error */;

    return p;
}

template<class T> T * guard_new(Error& e, T * p)
{
    if(e.failure())
    {
        delete p;
        return NULL;
    }

    return p;
}

Which would be used like this:

Derived o = guard_new(e, new(e) Derived(e));

Advantages of this technique include:

  • interoperability with C (if the Error class is declared appropriately)
  • thread-safe
  • zero size overhead in classes
  • the Error class can be 100% opaque; with the use of macros to access, declare and pass it around, it can include all sorts of information, including but not limited to source file and line, function name, stack backtrace, etc.
  • it applies to pretty complex expressions, making it almost like exceptions in many cases

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254501

C++ without exceptions is essentially a completely different language to C++, in which many of the idioms that give C++ its uniquely expressive power are rendered impotent. As you point out, constructors are stripped of their usefulness, and all nontrivial initialisation must be moved into a second-stage pseudoconstructor that can return an error indication. (Some people also advocate a matching pseudodestructor out of a misguided sense of symmetry, but that is completely pointless). Alternatively, the constructor could set a "constructed" flag on success, and each class could have a "constructed" method which checks this and all of its children.

If your company mandates that you disable exceptions, then you will also need a company-wide (or at least project-wide) convention to replace it. You will need to define a type for all (non-trivial) functions to return, and use that consistently everywhere - otherwise you'll get an unmaintainable hodge-podge of booleans and incompatible enumerations being passed around and manually converted at every level.

In this case, Foo will also need an Initialize method, which calls a.Initialize and bails out if that fails.

Upvotes: 7

Ashish
Ashish

Reputation: 8529

class Foo
{
private:
    AnotherClass a;
    bool m_bInitFail; //store the status of initialization failure

public:
    Foo(bool bInitFail = false) : m_bInitFail(bInitFail)
    {
        m_bInitFail  = a.Initialize();           
    }

    bool GetInitStatus () { return m_bInitFail ; }
};

int main()
{
  Foo fobj;
  bool bStatus = fobj.GetInitStatus();
  return 0;         
}

Upvotes: 0

mikelong
mikelong

Reputation: 3854

This is ugly and I don't really recommend it, but if you are not allowed to throw in the constructor you could have a dumb constructor and an init function:

class Foo
{
private:
    AnotherClass a;
public:
    Foo(){};
    bool initialize()
    {
        return a.Initialize();
    }
    ...
};

Foo obj;

Upvotes: 2

R Samuel Klatchko
R Samuel Klatchko

Reputation: 76541

If you don't want to use exceptions, there are two ways to let the caller know whether the constructor succeeded or not:

  1. The constructor takes a reference/pointer to a parameter that will communicate the error status to the caller.
  2. The class implements a method that will return the error status of the constructor. The caller will be responsible for checking this method.

If you go with either of these techniques, make sure your destructor can handle an instance where the constructor has failed.

Upvotes: 13

Todd Gardner
Todd Gardner

Reputation: 13521

There is not a good way; this is one of the major reasons they were added to the language in the first place. Without exceptions either:

  1. Perform some sort of assert() in the constructor to halt execution; impossible to ignore, but impossible to recover from.
  2. Do your actual construction in an Init function.
  3. ... or keep it within the constructor but set a "bad" flag.

Personally, I think 2 is strictly better than 3, as it doesn't increase class size, and makes it more visible when the "check" function isn't called. There are reasons I hear quoted, like you can access virtual functions, but I have always considered that to be fairly weak.

Upvotes: 3

anon
anon

Reputation:

two suggestions:

  • the old-fashioned setjmp/longjmp()
  • a global errno alike variable

Upvotes: 0

aJ.
aJ.

Reputation: 35460

why exceptions should not be used? The best way to return error from constructor is to throw the exception. The object which is constructed wrongly should not used and throwing exception ensures that.

You can refer this FAQ: How can I handle a constructor that fails?

Upvotes: 2

Related Questions