I've got deep into porting all memory allocation from malloc/free to new/delete.

First a C++ backgrounder -- those who know C++ can skip it.

One exception is char*, since we still use C library string functions and those
don't mix new char[]. strdup() does a malloc(), and you can't free() what you 
new'd;
similarly you can't delete what you malloc()d.

While in many cases the code below works, per standard it's undefined behavior:
char * foo = (char*)malloc(100 * sizeof(char));
...
delete foo; // undefined behavior (delete [] foo, the correct thing to do, will 
always crash)
char * foo = new char[100];
...
free(foo); // undefined behavior

The use of new/delete is needed to bring functionality from C-style 
constructor/free functions to
actual class member constructors/destructors.

The rationale is that C++ handles calling constructors and destructors as 
appropriate
when you new and delete class instances (we're talking language constructs, not 
Xcircuit
terminology). That way a whole class of errors goes away (failure to initialize 
or finalize
data structures), and the code where you use those classes becomes simpler.

C++ also gives you the power of operators, and I've already been able to simply
remove a few copies of list comparison code.

Another goodie that comes from C++: the RTTI (runtime type information system).
A class having any virtual methods has a pointer-size overhead that gives you
dynamic type information. So, in general, when porting from C to C++, you can 
drop
"type" fields: the virtual table pointer already does this job.

Here's how one uses it. Suppose you have two classes:

class generic {
public:
  virtual ~generic() {} // destructor, does nothing much
}

class derived : public generic {
}

And you instantiate them:

generic * a = new generic;
generic * b = new derived;

Then following hold:

assert(dynamic_cast<generic*>(a) != NULL); // dynamic_cast<type> is like 
Xcircuit/glib TO_type(ptr)
assert(dynamic_cast<generic*>(b) != NULL);
assert(dynamic_cast<derived*>(a) == NULL); // equivalent of  Xcircuit/glib 
style IS_DERIVED(a) == false
assert(dynamic_cast<derived*>(b) != NULL);

And you get not only dynamic casting, but type names and other goodies too:

printf("a's class is %s\n", typeid(*a).name().c_str()); // prints: a's class is 
generic
printf("b's class is %s\n", typeid(*b).name().c_str()); // prints: b's class is 
derived

End of backgrounder.



I've started with turning all elements into POD (plain old data -- no methods)
C++ classes, deriving from generic.

Then I've added a plist class that contains the parts and plist members. This 
class
is used by multiply-inheriting from generic and plist. Here's a path, for 
example:

 /*----------------------------------------------------------------------*/
/* Path                                                                 */
/*----------------------------------------------------------------------*/
struct path : public generic, public plist {
    u_short     style;
    float       width;
    inline path() : generic(PATH) {}
};
typedef path *pathptr;

I've got rid NEW_xxx macros, they are now proper functions:

static inline void NEW_PATH(pathptr* &a, plist *b) {
    a = b->append(new path);
}
Those should ideally morph into explicit constructors that take a plist*.

The plist has an append(generic*) method that does what you'd expect it to.

At this point the code compiled and worked.


Then I mechanically went through the code and turned all malloc()s for
non-pointer, non-char memory into news.

Since new type[] is not compatible with realloc(), I'm now pruning all uses of
realloc, by using appropriate container classes from Qt.

A common use of realloc() was to resize point lists. So I made pointlist
a class deriving from  QVector<XPoint>, and are in the process of changing
all of the relevant code to compile again. A few pointlist comparisons got wiped
out, since a XPoint has a compiler-defined operator== that does what you expect,
and thus a pointlist's operator== (defined by the QVector<> template class)
also does what you'd expect. That's exactly how C++ saves one lots of
menial, silly work. In some places the pointlist typedef was used where XPoint*
was really meant (a pointer-into-the-list, a.k.a. iterator rather than a list).

Then I'll tackle what remaining uses of realloc() there are.

Finally, free()s will be replaced with delete()s.

That should bring the code back into a working state.

Then I'll move all the constructor/destructor/operator functionality from 
detached
C functions into the classes themselves.

Next step: having generic derive from QGraphicsItem, and ensuing fun in pruning
code. Lots of code. Perhaps 10%+ outright in one swoop. If only the nights were
longer :)

QGraphicsItem automatically handles parent-child relationships, so our own 
plists
and whatnot will be gone in a blink, etc. But I'm conservative and want to keep 
the
code working at the end of each task. Now admittedly there's no testsuite, but 
that
can come later. Qt comes with a unit testing framework that can also exercise 
the GUI
elements (synthetic keypress/mouse events).

Cheers, Kuba
_______________________________________________
Xcircuit-dev mailing list
[email protected]
http://www.opencircuitdesign.com/mailman/listinfo/xcircuit-dev

Reply via email to