Resource Wrapper

Yeah, so I'll flesh this one out, as I understand it. -- RusHeywood

Pattern ResourceWrapper

Context: You need to allocate some sort of resource that your software will need to use for a bit, and then release them so as to be friendly to your platform. These resources can be things like open file handles, threads, memory, database transactions, IO port handles, etc.

Problem: The trouble is, forgetting to correctly release resources (i.e., a ResourceLeak) causes a huge number of software problems, the most common of these being MemoryLeaks. The consequences of failing to release these resources can be minimal, or they can be catastrophic and Byzantine, resulting in a filled open-file table or a system crash (especially if your system has not-so-great resource allocation facilities, such as MacOS Classic.)

Solution: Bind the scope of the resource allocation to the scope of a particular class of objects. Then, constructing and initializing such an object will result in the allocation of a single resource of some type. Similarly (and most importantly) destroying the object will result in the deallocation (freeing) of the resource. This strategy reduces all resource allocation worries to a single kind: object allocation.

Example: In communicating with a transaction-based database (which is every kind, these days), one must begin and end transactions in some regular fashion so that the DB engine can commit the changes made and release the "undo stack" that is created to ensure that your changes can be rolled back during the transaction if necessary. If one forgets to close/commit a transaction, there is no notification from the engine; it just gets slower and slower as more and more transactions are opened without a corrresponding close, until finally the database is restarted.

To reduce the worry of transaction closing, one might create a TransactionWrapper? which opens a transaction on construction, and closes the transaction when it is destroyed. (It's other methods typically also handle the other aspects of database communication, such as executing statements, but it isn't interesting to include that complexity for the example.)

   class TransactionWrapper? {
 private:
int transID;
Database *d;

public: TransactionWrapper? (Database *db) { d = db; transID = d->beginTransaction(); }

~TransactionWrapper? () { d->commitTransaction (transID); } }

One might then use a TransactionWrapper? within a function, like this:

    void writeUserToDatabase (Database *db) {
 TransactionWrapper? t(db);

// ... statement executions... }

Even though the programmer here did not explicitly include any code to end the transaction, the transaction was still committed successfully and quickly because the TransactionWrapper? used to manage the transaction was a stack variable within writeUserToDatabase. Since stack variables are destroyed as they go out of scope at the end of their containing function, the transaction was closed. If the programmer uses transactions in this way, no additional cleanup code was necessary, even if the function throws an exception or has multiple exit points.

Consequences: This strategy works extremely well when it is appropriate to use ResourceWrapper objects as stack variables. Then, deallocation is implicit regardless of how the containing function terminates, and the programmer need add no additional logic to free the resource. However, not all languages support stack-resident objects, and not all resource holdings are so short-lived that it makes sense for them to be bound to the scope of a function. Further consequences:

  void functionCall () {
      ResourceWrapper w;
      try {
  // resource allocation
  w = new ResourceWrapper (key);

// ... resource usage ...

} finally { // resource release w.releaseResource(); }


EditText of this page (last edited June 2, 2004) or FindPage with title or text search