Contents of the README.TXT file
Virtual DOS Heap Extender for C++ Programmers
Using Borland Compilers 2.0-3.1
(known alternately as PMDE, the "Poor Man's DOS Extender")
4. August 1993
I wrote this over the last several months. Pending approval, it will (I am
crossing my fingers) be published by Dr. Dobb's Journal.
This is a mechanism that will help you to transparently create as many objects
in your C++ application as your hard disk or EMS memory will hold. By
"transparently", I mean involving very little effort on your part! You can
use the new, ->, and * operators as you normally would.
You don't have to create and manage a template-oriented "virtual array" to use
it, and for most purposes you don't have to do any memory locking, either.
The idea here is that the 'new' operator is overloaded for VObject -- defined
in the included source modules -- and therefore automatically for all objects
descending (directly or indirectly) from VObject.
Just use VObject as a public base class for your own classes, and they will
behave as self-swapping virtual objects, going back and forth between
conventional memory and Disk/EMS as needed. The included example programs show
how to declare the objects and the pointers that reference them. The key is
the fact that the virtual objects are manipulated (and their members and
methods accessed) via smart pointer objects of the VPtr class. Declaring them
is a matter of using a statement like
VPtr(MyObject) p = new MyObject ("hello world",3);
rather than the usual
MyObject* p = new MyObject("hello world",3);
From then on in your program, p is pretty much used like a normal pointer.
Think of it as an 'overlay manager' for your C++ objects. The VPtr is smart
enough to know whether, during any given dereferencing operation, it must load
("cache") the object from its permanent store into conventional memory. It
all happens behind the scenes, as it were.
All of the messy issues like multiple references to a single object (like when
you pass a pointer to a C/C++ function) are resolved because of the VPtr's
doubly linked list implementation, which is explained in my article.
Also behind the scenes is a "VMemory" object which manages a cache of several
objects resident in conventional memory at any one time. Objects that aren't
used are, after a while, swapped out to their permanent store according to an
LRU algorithm. Whether the VMemory is based on a DiskArray or an EMSArray, as
well as the number of objects cacheable at once, is all managed by the call to
the VMemory constructor. The VMemory object (and there should be only ONE) is
a global object and should exist before main is called.
I have taken the appropriate precautions, like making sure VObject has a
virtual destructor. For convenience "GENERIC.H"-style declarations provide for
VPtr objects that can access the appropriate members and methods for derived
You can start right off programming with the DiskArray, or run the included
demos and compare the disk's and EMS memory's relative speed. EMS is fast in
any case, but disk is admittedly slow even for RAMDISKs and/or SMARTDRV-cached
To run EX1 and EX2.CPP, put them in the project file in lieu of TEST.CPP...
NOTE: In order to link in and use the EMSArray object, you must
(1) get the source code EMMC.C from Michael Tischer's "PC Intern
System Programming" and strip out the main() function.
(2) include it in the Borland project file, and modify FLATARRY.H
such that _EMS_ is #defined as 1.
Optionally, since other books contain such EMS interface modules written in C,
you might elect to change the EMS function prototypes -- found also in
FLATARRY.H -- to accommodate the differences. Only the first quarter of the
64k page frame is used.
Since in C++ standard 3.0, the 'delete' operator is inapplicable to anything
but the address of the heap object to be deleted (don't tell me the Committee
didn't see that one coming...) I was forced to substitute the Delete(VPtr&)
function as a substitute. All it means is that where before you could write
'delete p' for a MyObject* variable p, now you have to write 'Delete(p)' for
the VPtr(MyObject) variable p.
If you want to use potentially bottomless method recursion within method
calls, or use your virtual objects to contain VPtrs referencing other virtual
objects, there is a caveat. These cases can result in objects being swapped
out unsafely, i.e. before the return of the virtual object's method call! The
danger is that the implicit parameter 'this' is passed to the method, and it
is not a VPtr object, but rather a simple C++ pointer referencing the virtual
object. Cure this by temporarily "locking" your objects into memory: TEST.CPP
contains two examples of this.
If you like multiple inheritance (which I have heard described as the "goto of
the 90's"), there is yet another caveat. VObject must be the first thing
(memorywise) within your multiply descended class. Therefore follow these
rules of thumb, as a safeguard.
(a) When deriving class C from classes A and B, either A or B may be
descended from VObject; but not both.
(b) When deriving class C from classes A and B, whichever inherits from
VObject should be listed first in the inheritance list following the
My personal opinion, is that M.I. is something akin to digitally oscillating
your wiener. Any time casting a pointer changes its value, well .... enough
editorial for now.
If you like the "PMDE" alternative to the "DPMI" extenders, then please send
absolutely no money to me, Dan Moore, at 4 Hoffield Ct, Baltimore MD 21228.
But if you have bugs or gripes to report then I would be happy, in a tempered
sort of manner, to hear them. Just don't go basing your huge Database-
Management-or-Who-Knows-What home programming project on it just yet. I have
given the virtual objects quite a successful workout with TEST.CPP, but -- as
Microsoft and even Borland can tell you -- a release date is never a promise
of being bug-free. I therefore cannot be held liable for any loss of data or
sanity on your part.