Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions from a constructor means that my instance is out of scope afterward

I have a class whose constructor may throw an exception. Here’s some code that will catch the exception:

try {
    MyClass instance(3, 4, 5);
}
catch (MyClassException& ex) {
    cerr << "There was an error creating the MyClass." << endl;
    return 1;
}

But of course no code after the try/catch can see instance because it’s now out of scope. One way to resolve this would be to declare and define instance separately:

MyClass instance;
try {
    MyClass instance(3, 4, 5);
}
...

except that my class doesn’t have the appropriate zero-argument constructor. In fact, this case right here is the only one in which such a constructor would even make sense: the MyClass object is intended to be immutable, in the sense that none of its data members change after construction. If I were to add a zero-argument constructor I’d need to introduce some instance variable like is_initialized_ and then have every method check to make sure that that variable is true before proceeding. That seems like far too much verbosity for such a simple pattern.

What is the idiomatic way to deal with this kind of thing? Do I need to suck it up and allow instances of my class to be declared before they’re initialized?

like image 474
bdesham Avatar asked Nov 30 '22 19:11

bdesham


2 Answers

You should be doing everything you need to do inside the try block:

try {
    MyClass instance(3, 4, 5);

    // Use instance here
}
catch (MyClassException& ex) {
    cerr << "There was an error creating the MyClass." << endl;
    return 1;
}

After all, it is only within the try block that instance has been successfully created and so can be used.

I do wonder whether your catch block is really handling the exception. If you can't do anything to resolve the situation, you should be letting it propagate.

like image 124
Joseph Mansfield Avatar answered Dec 04 '22 13:12

Joseph Mansfield


Dynamically allocate the instance using new:

std::unique_ptr<MyClass> instance;
try
{
    instance.reset(new MyClass(3, 4, 5));
}
catch (const MyClassException& ex)
{
    std::cerr << "There was an error creating the MyClass." << std::endl;
    return 1;
}
// use instance as needed...
like image 37
Remy Lebeau Avatar answered Dec 04 '22 13:12

Remy Lebeau