IBM ILOG Solver User's Manual > Extending the Library > Writing a Goal: Car Sequencing > Writing your own goal > Arguments of goals: Traps and pitfalls |
Arguments of goals: Traps and pitfalls |
INDEX
![]() |
Goals are not executed immediately when they are called. However, their arguments are computed immediately, and they are saved together with the goal on the goal stack. Those arguments and computations are used when the goal is executed, generally after the function calling the goal has returned.
Note |
For that reason, arguments should not contain pointers to automatic objects, where automatic objects are objects allocated on the C++ stack, that is, without using the new operator.
|
Consider the following goals:
ILCGOAL1(PrintI, IlcInt*, i){ cout << *i << endl; return 0; } ILCGOAL1(CallPrintI, IlcInt*, i){ IlcInt i = 0; return PrintI(&i); // error here: i is an automatic } |
If the goal CallPrintI
is executed, PrintI
is called. This (among other effects) stores the address of i
. Then the function executing the body of CallPrintI
returns. Thus the address of i
is no longer a valid address. Finally, the goal PrintI
may be executed, causing an error since the address of i
is no longer valid.
Another subtle point is that arguments are computed before goal execution actually takes place. That fact can lead to some problems. A simple example requires the use of a constrained integer variable.
Consider the following incorrect code:
ILCGOAL1(WrongGoal, IlcIntVar, x){ return IlcAnd(IlcInstantiate(x), PrintX(getManager(), x.getValue())); // error: x is unbound } |
Here is the way that goal was intended to be executed: the constrained integer variable should be bound by the execution of the goal IlcInstantiate
; then the execution of the goal PrintX
should print its value. However, the argument of PrintX
is computed before IlcInstantiate
is executed. That order of events causes an error since x
is not yet bound. Indeed, IlcInstantiate
is pushed onto the goal stack, but it is not executed immediately.
Here is the correct way to pass x
as an argument (instead of passing its value):
ILCGOAL1(PrintVar, IlcIntVar, x){ cout << x.getValue() << endl; return 0; } ILCGOAL1(RightGoal, IlcIntVar, x){ return IlcAnd(IlcInstantiate(x), PrintVar(getManager(), x)); // no error here } |
As indicated in this lesson the macros ILCGOALn
define subclasses of the class IlcGoalI
. Arguments to the macro are data members of the new class. The most significant consequence of that fact is that modifications of those arguments in the body of the macro are saved. Such modifications often have unfortunate results, and you are strongly advised not to make such modifications.
© Copyright IBM Corp. 1987, 2009. Legal terms. | PREVIOUS NEXT |