CREATE() overloading

Posted by Greven on Sat 11 Dec 2004 04:20 AM — 4 posts, 15,555 views.

Canada #0
Function overloading in C++ seems to me to be a great feature, and as I am reading up on the difference between C and C++, I've just come across this. Now, I understand that overloading for functions that are not similiar is in bad style, my question I guess is what are peoples opinions on using the CREATE macro, since its litered everywhere, to call a create function that is overloaded for all the different types of structures used. To me this seems like a fairly good way to ensure that initialization is done properly every time something is created, and provides the functionality of one function to use. The same could also be applied to freeing as well. Is this a preferable way to do things, or is another options, such as class constructors and destructors a better choice?
USA #1
If you're trying to ensure initialization at memory allocation, then the way to do it is with constructors.

Note that in C++ a struct is a class-in-disguise (where everything is public and public only), so you can have constructors/destructors on structs as well as classes.

If you're using C++, I would just throw away the silly create macro and only make calls to 'new'. Of course, this means that you have to throw away calls to 'free' (destroy) and replace them with calls to 'delete'.

In any case, if you do function overloading for the create function, you're basically reimplementing a lot of what 'new' does to begin with; it's somewhat of a waste of time.

One thing to think about is what belongs in the constructor, and what belons in other initialization functions. Perhaps you don't need to worry too much about this for the basic SMAUG model - most of the structs have "constructors" anyhow (such as create_mobile, create_object etc.)
USA #2
I agree on the point of ditching CREATE if you're going to be using C++ classes with constructors. As far as what to initialize and what not to, pass the code through Valgrind and it will happily tell you in the form of warnings about dependency on or use of uninitialized values.
Australia Forum Administrator #3
The problem with CREATE is it does a malloc (calloc anyway) which will *not* work if you start using classes inside your structures.

If you are going to use C++ you may as well enjoy the considerable benefits of STL, like strings, lists, maps etc.

It is *so* much easier to do linked lists, maps, queues, strings in STL that I could never go back to the old way.

Here is an example of the sort of thing you could change:


struct  cmd_type
{
    CMDTYPE *           next;
    char *              name;
    DO_FUN *            do_fun;
    int                 flags;  /* Added for Checking interpret stuff -Shaddai*/
    sh_int              position;
    sh_int              level;
    sh_int              log;
    struct              timerset        userec;
    int                 lag_count;      /* count lag flags for this cmd - FB */
};


Now the first thing you could do is make the name a string, rather than having to malloc the memory for it, eg.


struct  cmd_type
{
    CMDTYPE *           next;
    string              name;
    DO_FUN *            do_fun;
    int                 flags;  /* Added for Checking interpret stuff -Shaddai*/
    sh_int              position;
    sh_int              level;
    sh_int              log;
    struct              timerset        userec;
    int                 lag_count;      /* count lag flags for this cmd - FB */
};


However this *will* crash if you use CREATE, because the malloc/calloc does not call the string's constructor. You need to use new to create each command.

Then you can get rid of the linked list anyway, and use a map, eg.


struct  cmd_type
{
    DO_FUN *            do_fun;
    int                 flags;  /* Added for Checking interpret stuff -Shaddai*/
    sh_int              position;
    sh_int              level;
    sh_int              log;
    struct              timerset        userec;
    int                 lag_count;      /* count lag flags for this cmd - FB */
};

map<string, cmd_type> commands_map;


Now you can just add a command like this:


cmd_type look_command;
// fill out structure here 
commands_map ["look"] = look_command;


and find it:


cmd_type look_command = commands_map ["look"];


I'm not testing this as I type, so forgive me if this doesn't all compile perfectly. ;)

You can override the comparison routine for maps, so you could make the lookup case-insensitive. Or if you want to do stuff like the prefix checks, you can use a list instead:

list<cmd_type> commands_list;

Iterating over a list is very simple still.