Andrew Sun
Andrew Sun

Reputation: 4231

How to catch a constructor exception?

I have a C++ class which throws an exception from the constructor on failure. How can I allocate a local instance of this class (without using new) and handle any possible exceptions, while keeping the try block scope as small as possible?

Essentially, I am looking for the C++ equivalent of the following Java idiom:

boolean foo() {
    Bar x;
    try {
        x = new Bar();
    } catch (Exception e) {
        return false;
    }
    x.doSomething();
    return true;
}

I do not want to catch exceptions from x.doSomething(), only the constructor.

I suppose what I'm looking for is a way to separate the declaration and the initialization of x.

Is it possible to accomplish this without using heap allocations and pointers?

Upvotes: 13

Views: 3922

Answers (7)

songyuanyao
songyuanyao

Reputation: 172924

You can use std::optional from C++17:

bool foo() {
    std::optional<Bar> x; // x contains nothing; no Bar constructed
    try {
        x.emplace();      // construct Bar (via default constructor)
    } catch (const Exception& e) {
        return false;
    }
    x->doSomething();     // call Bar::doSomething() via x (also (*x).doSomething() )
    return true;
}

Upvotes: 15

Jarod42
Jarod42

Reputation: 217275

You have to choose between variant of

bool foo() {
    std::unique_ptr<Bar> x;
    try {
        x = std::make_unique<Bar>();
    } catch (const BarConstructorException& e) {
        return false;
    }
    x->doSomething();
    return true;
}

or

bool foo() {
    try {
        Bar x;
        x.doSomething();
    } catch (const BarConstructorException& e) {
        return false;
    }
    return true;
}

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409176

Yes it's possible, if you put all the code in the try clause, for example by using a function try block (to avoid unnecessary nesting and scoping):

bool foo() try
{
    Bar x;
    x.doSomething();
    return true;
}
catch (std::exception const& e)
{
    return false;
}

Or in the try clause call another function which does the real work:

void real_foo()
{
    Bar x;
    x.doSomething();
}

bool foo() try
{
    real_foo();
    return true;
}
catch (std::exception const& e)
{
    return false;
}

Note that it's often not a good idea to throw exceptions in a constructor, as that will halt the construction of the object, and its destructor will not be called.


As noted by Holt, this will also catch exceptions from the doSomething call. There are two ways of solving that:

  1. The simple and standard way: Use pointers.

  2. Use two-stage construction: Have a default constructor which can't throw exceptions, then call a special "construct" function that can throw exceptions.

The second way was common before C++ was standardized, and used extensively in code for the Symbian system. It is not common any more since using pointers for this is much more easy and simpler, especially today with good smart pointers available. I really don't recommend the second way in modern C++.

The easiest way is of course to make sure that the constructor can't throw exceptions at all, or if any is thrown then they are of the nature that the program can't continue anyway and have the program be terminated. As noted in the comments to your question, exceptions in C++ are expensive, and then we also have the abandoned construction issue, and in all using exceptions in C++ should only be done in exceptional cases. C++ is not Java, you should not treat it as such even if there are similar constructs in both languages.

If you still want to throw exceptions from the constructor there is actually a third way to catch only those: Use one of the code-example up top, and throw only specific exceptions that doSomething can never throw and then catch these specific constructors only.

Upvotes: 5

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145269

In the revised question the OP adds the requirement that

I do not want to catch exceptions from x.doSomething(), only the constructor [of the local variable].

A simple way to translate the Java code

boolean foo() {
    Bar x;
    try {
        x = new Bar();
    } catch (Exception e) {
        return false;
    }
    x.doSomething();
    return true;
}

… to C++, is then to use an Optional_ class (like Barton-Nackmann Fallible, boost::optional or C++17 std::optional)

auto foo()
    -> bool
{
    Optional_<Bar> xo;
    try
    {
        xo.emplace();
    }
    catch( ... )
    {
        return false;
    }

    Bar& x = *xo;
    // Possibly other code here, then:
    x.doSomething();
    return true;
}

A nice alternative is to refactor that code, like this:

struct Something_failure {};

void do_something( Bar& o )
{
    // Possibly other code here, then:
    o.doSomething();
}

auto foo()
    -> bool
{
    try
    {
        Bar x;

        do_something( x );
        return true;
    }
    catch( Something_failure const& )
    {
        throw;
    }
    catch( ... )
    {}
    return false;
}

If you do not like the above approaches then you can always go for a dynamically allocated Bar instance, e.g. using a std::unique_ptr for guaranteed cleanup, which however has the general overhead of a dynamic allocation. In Java most every object is dynamically allocated so that might not seem to be a serious disadvantage. But in C++ most objects are superfast stack-allocated so that a dynamic allocation is a very slow operation compared to ordinary operations, so the possible conceptual simplicity of dynamic allocation must be weighted against that.

Upvotes: 1

rocambille
rocambille

Reputation: 15976

No. From your java example, you will have to choose between these 2 possibilities:

Without pointers:

bool foo() {
    try {
        Bar x;
        x.doSomething();
    } catch (Exception e) {
        return false;
    }
    return true;
}

With pointers:

bool foo() {
    Bar* x = nullptr;
    try {
        x = new Bar();
    } catch (Exception e) {
        return false;
    }
    x->doSomething();

    delete x; // don't forget to free memory

    return true;
}

Or using managed pointers:

#include <memory>

bool foo() {
    std::unique_ptr<Bar> x;
    try {
        x = new Bar();               // until C++14
        x = std::make_unique<Bar>(); // since C++14
    } catch (Exception e) {
        return false;
    }
    x->doSomething();
    return true;
}

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234705

This Java idiom doesn't translate well to C++ since Bar x; will require default constructor even if your real constructor requires arguments to be passed.

I'd advise fighting the language to this degree - widening the try block is sufficient - but if you really want to narrow then you could use a function and rely on return value optimisation to obviate a value copy:

Bar foobar()
{
    try {
        return Bar();
    } catch (Exception& e){
        /* Do something here like throwing a specific construction exception
           which you intercept at the call site.*/
    }
}

But really, you could throw a specific exception on construction, so obviating this function approach entirely.

Upvotes: 6

Smeeheey
Smeeheey

Reputation: 10316

Normally if you want to avoid heap allocations, you can't separate the declaration of a local variable from its definition. So if you were to combine everything in a single function, you would have to do surround the entire scope of x with try/catch block:

boolean foo() {
    try {
        Bar x;
        x.doSomething();
    } catch (Exception e) {
        return false;
    }
    return true;
}

Upvotes: 2

Related Questions