Topic
  • 5 replies
  • Latest Post - ‏2013-11-28T14:34:52Z by PhilippeLaborie
Tulkas
Tulkas
4 Posts

Pinned topic The destructor of my custom constraint is never called.

‏2013-11-27T15:09:28Z |

Hello,

 

I was wondering why the destructor of the following custom constraint is not executed when I call either c.end() ou env.end(), although the constructor is clearly called during extraction... I have indeed huge memory leaks due to this behaviour. How can I manage to call the destructor of a custom constraint when the environment is released ? Should I implement durty tricks to be sure the integer pointed by test is deleted manually ?

 

Best regards,

 

*******************************************

#include <ilcp/cp.h>
#include <ilcp/cpext.h>

class ConstraintI : public IlcConstraintI

{
private:

    int **test;

public :
    ConstraintI(IloSolver solver,int** _test):IlcConstraintI(solver),test(_test) { *test = new int(5); }
    virtual ~ConstraintI();
    void post();
    void propagate();
};

ConstraintI::~ConstraintI() { delete *test; }
void ConstraintI::post() {}
void ConstraintI::propagate() {}

ILOCPCONSTRAINTWRAPPER1(MyConstraint,cp,int**,test)
{
    return new (cp.getHeap()) ConstraintI(cp,test);
}

void app(int **test)
{

    std::cout << std::endl;
    IloEnv env;
    IloModel problem(env);
    IloCP solver(env);

    IloConstraint c = MyConstraint(env,test);
    problem.add(c);

    solver.extract(problem);
    solver.solve();

    c.end();
    env.end();

}

int main()
{
    int *test = nullptr;
    app(&test);
    std::cout << *test << std::endl;
    return 0;

}

*******************************************

OUTPUT :

"5" (I would like a SEGFAULT since ~ConstraintI should be called !)


*******************************************
Updated on 2013-11-27T15:11:13Z at 2013-11-27T15:11:13Z by Tulkas
  • PhilippeLaborie
    PhilippeLaborie
    50 Posts

    Re: The destructor of my custom constraint is never called.

    ‏2013-11-28T08:43:19Z  

    Hello,

    The destructor is indeed not called. In fact the engine cannot really call such a desctructor because it is you who created the object.

    What you should do is to allocate the internal objects of the constraint on the CP Optimizer heap rather than on the C++ heap.

    *test = new (solver.getHeap()) int(5)
    

    That way, the memory will be released when the solver (or the env) is ended because everything allocated on the engine heap is released.

    Philippe

  • Tulkas
    Tulkas
    4 Posts

    Re: The destructor of my custom constraint is never called.

    ‏2013-11-28T08:52:59Z  

    In this example, I took an int but, in practice, I must allocate another IloEnv object and solve an LP (a subproblem solved with CPLEX).

     

    The bounds of the variables of this subproblem are updated* according to the bounds** of the master problem and the problem is re-solved at each call of propagate().

     

    Will the memory be released if the end() method of this subenvironment is not called, i.e. will the memory of this sub IloEnv object be allocated on the stack OR the handler will be on the stack and the implementation in the general stack ?

     

    Best regards,

     

    * IloNumVar::setBounds(lb,ub)

    ** IlcIntVar::getMin() / getMax()

  • PhilippeLaborie
    PhilippeLaborie
    50 Posts

    Re: The destructor of my custom constraint is never called.

    ‏2013-11-28T09:16:39Z  
    • Tulkas
    • ‏2013-11-28T08:52:59Z

    In this example, I took an int but, in practice, I must allocate another IloEnv object and solve an LP (a subproblem solved with CPLEX).

     

    The bounds of the variables of this subproblem are updated* according to the bounds** of the master problem and the problem is re-solved at each call of propagate().

     

    Will the memory be released if the end() method of this subenvironment is not called, i.e. will the memory of this sub IloEnv object be allocated on the stack OR the handler will be on the stack and the implementation in the general stack ?

     

    Best regards,

     

    * IloNumVar::setBounds(lb,ub)

    ** IlcIntVar::getMin() / getMax()

    No, the memory of the sub IloEnv won't be released here, only the handle. So in this case, you should call env.end() yourself on this sub IloEnv.

    Philippe

  • Tulkas
    Tulkas
    4 Posts

    Re: The destructor of my custom constraint is never called.

    ‏2013-11-28T13:52:41Z  

    No, the memory of the sub IloEnv won't be released here, only the handle. So in this case, you should call env.end() yourself on this sub IloEnv.

    Philippe

    Thank you for your answer !

     

    I think this behaviour should be clearly stated in the documentation. Thanks to valgrind, I also found several memory leaks which were due to an AUTOMATICALLY allocated (on the cp heap) std::vector object whose underlying array was not released when my environment was ended.

     

    In particular,

    ~MyConstraintI(); // the destructor, generally empty"

    >> It supposes that the destructor is called, even it generally does nothing...

     

    Best regards,

  • PhilippeLaborie
    PhilippeLaborie
    50 Posts

    Re: The destructor of my custom constraint is never called.

    ‏2013-11-28T14:34:52Z  
    • Tulkas
    • ‏2013-11-28T13:52:41Z

    Thank you for your answer !

     

    I think this behaviour should be clearly stated in the documentation. Thanks to valgrind, I also found several memory leaks which were due to an AUTOMATICALLY allocated (on the cp heap) std::vector object whose underlying array was not released when my environment was ended.

     

    In particular,

    ~MyConstraintI(); // the destructor, generally empty"

    >> It supposes that the destructor is called, even it generally does nothing...

     

    Best regards,

    In fact the behavior is quite simple and there is no magic inside:

    - the destructor of the constraint is not called by CP Optimizer because it is you who called the constructor. The engine cannot take the initiative to call the destructor

    - concerning the engine heap, only the memory allocated on this heap (with the 'new' operator) is released when the engine is ended. If you have a class X allocated on the engine heap with X* x = new (cp.getHeap()) X(...), when the engine is ended, it will release the memory used by X but of course not the memory allocated on other heaps (like for instance if some data of object X point to some memory allocated on the C++ heap)

    Philippe