Catching exceptions

Exception handling for managing anomalies is a good programming practice when using CP Optimizer.

When programming an application, it is a good programming practice to enclose parts of your application in try-catch statements. In that way, when anomalies arise during execution, they can be managed as exceptions, so that your application can recover as cleanly as possible. You will find samples of try-catch statements in the examples distributed with CP Optimizer.

If you use try-catch statements, it is possible to distinguish exceptions raised by CP Optimizer from exceptions raised by the rest of the application. Specifically, when an error condition is encountered, CP Optimizer raises an exception of type IloException. Your application can catch these exceptions within try-catch statements, and you can thus determine directly whether the anomaly arises within the CP Optimizer part of your application or in another part of your application. Here’s the conventional way to catch an error exception from CP Optimizer in the C++ API:


catch (IloException& e) {
  ...
  e.end();
}

The reference manual documents exceptions specific to IBM® ILOG® Concert Technology and CP Optimizer.

Note:

Catch exceptions by reference

Catch exceptions by reference, not by value, to avoid losing information and to prevent leaks from expressions or arrays.

In the C++ API, exception classes are not handle classes. Thus, the correct type of an exception is lost if it is caught by value rather than by reference (that is, using catch(IloException& e) {...}). This is one reason that catching IloException objects by reference is a good idea, as demonstrated in all the examples distributed with CP Optimizer. Some derived exceptions may carry information that would be lost if caught by value. So if you output an exception caught by reference, you may get a more precise message than when outputting the same exception caught by value.

There is a second reason for catching exceptions by reference. Some exceptions contain arrays to communicate the reason for the failure to the calling function. If this information were lost by calling the exception by value, the method end could not be called for such arrays, and their memory would be leaked (until env.end is called). After catching an exception by reference, calling the end method of the exception will free all the memory that may be used by arrays (or expressions) of the actual exception that was thrown.

You can also control where warnings and error messages of the CP Optimizer part of your application are displayed. For example, during debugging, you might want all warning or error messages directed to your monitor, whereas when your application goes into production for use by customers, for example, you might want to direct warnings and error messages to a log file or some other discreet channel.

In the C++ API of Concert Technology, the class IloEnv initializes output streams for general information, for error messages and for warnings. The class IloAlgorithm supports these communication streams and the class IloCP inherits its methods. For general output, there is the method IloAlgorithm::out. For warnings and nonfatal conditions, there is the method IloAlgorithm::warning. For errors, there is the method IloAlgorithm::error.

In the C++ API, an instance of IloEnv defines the output stream referenced by the method out as the system cout in the C++ API, but you can use the method setOut to redefine it as you prefer. For example, to suppress output to the screen in a C++ application, use this method with this argument:


setOut(IloEnv::getNullStream())

Likewise, you can use the methods IloAlgorithm::setWarning and setError to redefine those channels as you prefer.

In the Microsoft .NET Framework languages and Java™ APIs, the native streams are used directly.