C++ RAII compared with Java Dispose pattern

Earlier today I wrote that: “The C++ destructor model is exactly the same as the Dispose and using patterns, except that it is far easier to use and a direct language feature and correct by default, instead of a coding pattern that is off by default and causing correctness or performance problems when it is forgotten.“ Niclas Lindgren agreed with the post but added:

...although you use the word coding pattern to confuse something simple with something that sounds trickier.

I was referring to the Dispose coding pattern. For the benefit of those who aren't familiar with the Java Dispose pattern, let me give two examples: first a simple one with just one resource, then a more complex one with three resources. The examples use .NET Framework types.

Consider this C++/CLI code:

String^ ReadFirstLineFromFile( String^ path ) {
StreamReader r(path);
return r.ReadLine();
}

The minimal C# equivalent is the “using“ patterns which semiautomates the Java Dispose pattern (I'm showing the {} around the block to be explicit that there's a block, although since there's only one statement you don't really need them):

String ReadFirstLineFromFile( String path ) {
  using ( StreamReader r = new StreamReader(path) ) {
    return r.ReadLine();
  }
}

The minimal Java equivalent is the Dispose pattern (this is what C#'s “using“ generates under the covers):

String ReadFirstLineFromFile( String path ) {
  StreamReader r = null;
  String s = null;
  try {
    r = new StreamReader(path);
    s = r.ReadLine();
  } finally {
    if ( r != null ) r.Dispose();
  }
  return s;
}

I called this Dispose pattern “a coding pattern that is off by default and causing correctness or performance problems when it is forgotten.“ That is all true. You have to remember to write it, and you have to write it correctly. In constrast, in C++ you just put stuff in scopes or delete it when you're done, whether said stuff has a nontrivial destructor or not.

But that example is still flattering to the Dispose pattern, because there's only one resource. Consider as a second example this C++ code that opens a message queue and echoes one message to two target queues (a main queue and a backup queue) -- and automatically correctly closes the queues:

void Transfer() {
MessageQueue source( "server\\sourceQueue" );
String^ qname = (String^)source.Receive().Body;
MessageQueue dest1( "server\\" + qname ), dest2( "backup\\" + qname );

  Message^ message = source.Receive();
dest1.Send( message );
dest2.Send( message );
}

The minimal correct Java equivalent is:

void Transfer() {
MessageQueue source = null, dest1 = null, dest2 = null;
try {
source = new MessageQueue( "server\\sourceQueue" );
String qname = (String)source.Receive().Body;
dest1 = new MessageQueue( "server\\" + qname );
dest2 = new MessageQueue( "backup\\" + qname );

    Message message = source.Receive();
dest1.Send( message );
dest2.Send( message );
}
finally {
if( dest2 != null ) { dest2.Dispose(); }
if( dest1 != null ) { dest1.Dispose(); }
if( source != null ) { source.Dispose(); }
}
}

In this case, the queues will be freed up eventually when the garbage collector runs (which it probably will). In the meantime, we've tied up scarce resources. Worse, we've tied up resources on other machines.

So the C++ destructor model is exactly the same as the Dispose and using patterns, except that it is far easier to use and a direct language feature and correct by default, instead of a coding pattern that is off by default and causing correctness or performance problems when it is forgotten.