 | Hi all,
Yep, I'm still working on Streams :)
There is another problem with the C++NPv2 p302 example. The example inherits from ACE_Module<>, and then the modules are inserted into a stream via their base-class pointers. i.e., they're being used polymorphically.
However, ACE_Module<>'s destructor is NOT virtual, so any derived object destructor will not be called. This means that the task_ member of that class will 'leak', i.e., never be destroyed.
The examples in APG, Chapter 18, p381 use a
typedef ACE_Module Module;
and then call the ACE_Module constructor directly, i.e., they do not use inheritance. So that form of example would work fine.
Later the CommandModule is defined on p402 and that does inherit from ACE_Module<>. However, in that case the inherited class does not define any member variables, it just modifies the constructor interface and introduces a new function that internally casts the argument contained within the underlying base class. So, there would be no problems with this type of inheritance.
However, its particularly misleading as both examples suggest that inheriting from ACE_Module is one of the intended uses of this class.
The C++NPv2 example could use inheritance in the same way as the APG, however, the template for the class would instead need to dynamically allocate the task in the constructor body, and then pass that task down to the module baseclass and set the appropriate delete flag. This scheme replaces the constructor with the shortened version (fewer arguments), and does not introduce any new member variables, so the fact that the derived destructor is not called does not leak. However, its disconcerting if you have a trace/debug statement in your destructor and it never gets called!
Making the ACE_Module destructor virtual seems like a cleaner solution!
An example of the issue:
http://www.ovro.caltech.edu/~dwh/ace/ace_module_not_virtual.cpp
http://www.ovro.caltech.edu/~dwh/ace/ace_module_not_virtual.txt
---------------------------------------- Main: Stack module object Task: constructor Task: constructor Module: constructor Module: destructor Task: destructor Task: destructor ---------------------------------------- Main: Dynamic module object assigned to a pointer of the same type Task: constructor Task: constructor Module: constructor
Main: Delete it Module: destructor Task: destructor Task: destructor ---------------------------------------- Main: Dynamic module object assigned to a pointer of the base type Task: constructor Task: constructor Module: constructor
Main: Delete it
The example creates a stack object, and you can see its contents destruct when it goes out of scope. Similarly when a dynamically allocated module is assigned to a pointer of its type, and then that object is deleted, it also destructs. However, when the dynamically allocated module is assigned to a base class pointer (ACE_Module) the call to delete only deletes the base-class ... oops resource leak.
Since the Streams interface uses pointers to ACE_Modules<>, and it is responsible for DELETING them, the class passed in either has to BE an ACE_Module, or has to derive polymorphically from ACE_Module (which it can't, since the destructor is not virtual).
Why does this matter? Well, I see the whole point of the streams interface as being able to create a whole suite of pre-canned modules, that I can then plug together to create different applications:
eg. producer consumer -------- -------- Simulator FileWriter Hardware Server Client
So I can plug a similator into a filewriter and generate a set of test data (CDR-encoded), I can then take it into MATLAB and plot it. Then I change the simulator for real hardware, write the data to file, and check it. Then I plug the hardware into a server, and a client into a filewriter and I check I can send data across the network and read it ok. Then I plug multiple sets of hardware into multiple servers, and then create multiple clients that collect all that data and pipe it to either a filewriter or another server. This small set of modules can generate a whole suite of applications. I'm trying to save myself some code maintenance here! :)
The hardware is an array of radio telescopes:
http://www.ovro.caltech.edu/~dwh/correlator/
Cheers Dave Hawkins Caltech.
|
|