next up previous contents index
Next: "list-alloc" and "list-free" Up: Memory Management Previous: Memory Management

"new-instance", "delete" and "free"

 

The methods "new-instance" and "free" must be written for every new class that adds instance variables to its superclass. If the new class has no additional instance variables the superclass methods can be used via inheritance.

   (INSTANCE * ) GRAPE(class, "new-instance")(name)
CLASS * class
char * name
first must call "new-instance" on its superclass to allocate memory for a new instance of class class named name. The superclass method will initialize its instance variables and return the pointer to the created instance (again NULL indicates an error). Then the instance variables of the class have to be initialized, finally the pointer to the new instance is returned.

To avoid problems with inheritance the only parameter of a "new-instance" method should be the name of the new instance, only on interactive classes this might be different (see sections 5.5.2 and 9.1). If instances of a class should be archived with the GRAPE archiving methods a different parameter list will get you into trouble -- you probably won't be able to read the data back in.

The counterpart of the "new-instance" method is

   GRAPE(inst, "delete")()
INSTANCE * inst
This method will delete a reference to an object or -- if the object isn't referenced from somewhere else -- the object itself, in this case the "free" method is called.

It is not possible to add "delete" methods, this method is only allowed for class Root. If a class needs a special refcount handling a "zero-refs" method has to be implemented, see section 5.4.5.2 below.

   (INSTANCE * ) GRAPE(inst, "free")()
INSTANCE * inst
This method has to free all memory that was allocated for its instance variables (not only the memory allocated by "new-instance"). By calling "free" on the superclass the superclass' instance variables are freed and finally Root "free" will free the memory for the instance struct.

Of course the superclass "free" method must be called at the end of the method because Root "free" frees the instance itself, afterwards the instance pointer is no longer valid.

"free" must return NULL and it can only be called by "delete", this is done if the instance can be freed since it isn't referenced anymore. Not calling "free" on the superclass, calling it directly or not returning NULL will result in an error.

Now we present the first methods for the demo class Rot2d. The following listing contain lots of detailed comments, it should be no big problem to understand how things are done.

ROT2D *rot2d_new_instance(char *name)
{
  CLASS *class;
  ROT2D *self;
  TRIANG1D *curve, *axis;

  /*
   * START_METHOD returns the object the method was called on.
   * "new-instance" is always a class method, therefore G_CLASS
   * is used as parameter.
   */
  class = (CLASS *)START_METHOD(G_CLASS);

  /*
   * The return value is checked because the method could have
   * been called on an instance, then START_METHOD returns NULL.
   * If an error occurs a method always should return NULL, so
   * this is what we do if we get no class.
   */
  ASSURE(class, "", END_METHOD(NULL));

  /*
   * First we have to allocate memory for our instance, we call
   * "new-instance" on our superclass (using ^). Again we check
   * the return value to see if enough memory was available.
   */
  self = (ROT2D *)GRAPE(class, "^new-instance")(name);
  ASSURE(self, "rot2d_new_instance: can't create instance", END_METHOD(NULL));

  /*
   * We allocate memory for curve and axis by calling "new-instance"
   * on their class Triang1d, again these checks...
   */
  curve = self->curve = (TRIANG1D *)GRAPE(Triang1d, "new-instance")("curve");
  axis = self->axis = (TRIANG1D *)GRAPE(Triang1d, "new-instance")("axis");
  ASSURE(curve && axis,
         "rot2d_new_instance: can't create curve/axis",
         { GRAPE(self, "delete")(); END_METHOD(NULL); });

  /*
   * Only the structure for curve/axis was allocated by "new-instance".
   * We now use "list-alloc" to allocate memory for the coordinate lists,
   * in this case for three/two points. We define our points and set the
   * number of points to the right value.
   */
  GRAPE(curve, "list-alloc")(3);
  curve->x[0] =  0.5; curve->x[1] =  0.5; curve->x[2] =  0.5;
  curve->y[0] = -0.5; curve->y[1] =  0.0; curve->y[2] =  0.5;
  curve->z[0] =  0.0; curve->z[1] =  0.0; curve->z[2] =  0.0;
  curve->number_of_points = 3;

  GRAPE(axis, "list-alloc")(2);
  axis->x[0] =  0.0; axis->x[1] =  0.0;
  axis->y[0] = -1.0; axis->y[1] =  1.0;
  axis->z[0] =  0.0; axis->z[1] =  0.0;
  axis->number_of_points = 2;

  /*
   * The other instance variables get default values, too. The
   * default point for editing is the middle point of the curve.
   */
  self->angle = 360.0;
  self->discr = 24;

  self->current = 1;

  /*
   * We return the instance we have created.
   */
  END_METHOD(self);
}


ROT2D *rot2d_free()
{
  ROT2D *self;

  /*
   * This is an instance method, therefore G_INSTANCE is used.
   * Again the return value is checked, somebody might have called
   * "free" on the class Rot2d (or a subclass).
   */
  self = (ROT2D *)START_METHOD(G_INSTANCE);
  ASSURE(self, "", END_METHOD(NULL));

  /*
   * First we have to delete curve and axis...
   */
  if(self->curve)
    GRAPE(self->curve, "delete")();
  if(self->axis)
    GRAPE(self->axis, "delete")();

  /*
   * Now calling "free" on the superclass will free any memory
   * allocated for the surface of revolution (this is done by
   * Triang2d "free") and the memory for the instance struct
   * (Triang2d "free" calls "free" on its superclass, too).
   */
  GRAPE(self, "^free")();

  /*
   * Free methods should always return NULL...
   */
  END_METHOD(NULL);
}

New methods have to be added to their class by "add-method". Therefore we extend the main program, this has to be done for all following methods (the full listing can be found in section 5.5.7):

#include <grape.h>
#include "rot2d.h"


CLASS *Rot2d = NULL;


int main()
{
  Rot2d = (CLASS *)GRAPE(Triang2d, "new-class")("Rot2d", sizeof(ROT2D));
  ASSURE(Rot2d, "main: can't create class Rot2d", return 5);

  GRAPE(Rot2d, "add-method")("new-instance", rot2d_new_instance);
  GRAPE(Rot2d, "add-method")("free", rot2d_free);

  ...
}

next up previous contents index
Next: "list-alloc" and "list-free" Up: Memory Management Previous: Memory Management

SFB 256 Universität Bonn and IAM Universität Freiburg

Copyright © by the Sonderforschungsbereich 256 at the Institut für Angewandte Mathematik, Universität Bonn.