C++ Variable Shadowing

In C++, you can declare a variable in a derived class with the exact same name as the base class. This is allowed because each variable is properly scoped. Shadowing can lead to some fairly unpredictable behavior.

Consider a class that supports reference counting used with smart pointers (IncRef, GetRef, copy and assignment operators omitted for brevity).

   1: class Base 
   2: {
   3:     void DecRef { m_count--; if (!m_count) delete this; }
   4:  
   5:     int m_count;
   6: }

Now imagine you create a derived class but also add a reference count:

   1: class Derived : public Base
   2: {
   3:     void DecRef() ...
   4:  
   5:     int m_count;
   6: }

Derived now has two reference counts. This isn’t a problem if you don’t assign a Derived object to a Base smart pointer (assuming your smart pointers can do the type conversion automatically). Once you do this assignment, however, bad things happen. For example:

   1: SmartPointer<Derived> sp1 = new Derived();   // m_count = 1
   2: // later...
   3:  
   4: SmartPointer<Base> sp3 = sp1;                // Base::m_count=1, Derived::m_count=1
   5:  
   6: // sp3 falls out of scope,                      Base::m_count=0, Derived::m_count=1
   7:  
   8: // Whops, Base::m_count went to zero and the original object was deleted.
   9: // Anyone using sp1 has a null pointer / deleted variable to work with instead
  10: // of a valid instance.

Why would anyone add reference counting to Derived when it is already included in Base? You wouldn’t intentionally do this (at least I hope you wouldn’t). In this particular instance, a sequence of small code changes lead to a brilliant runtime failure.

Base was not reference counted initially, it was an abstract class with pure virtual functions. Each derived class was responsible for deciding whether to support reference counting or not. Sometime later Base was made a concrete class with it’s own referencing counting. This change was made without going back and updating all the derived classes.

The resulting error went undetected until much later when a Derived smart pointer was assigned to a Base smart pointer; at some point the Base smart pointer fell out of scope, deleted it self, and then later an attempt was made to access the Derived smart pointer. Result: a pure virtual function assert at runtime.

With some compilers (like gcc) you can enable warnings that at least tell you when this happens. I thought we had enable this using –WAll. It turns out there’s another compiler flag for just this situation, –Wshadow that isn’t included in –Wall.

   -Wshadow
Warn whenever a local variable shadows another local variable,
parameter or global variable or whenever a built-in function is
shadowed.

I haven’t found the equivalent in Visual Studio 2005 or 2008.

Book Review: Beautiful Code

I finished reading "Beautiful Code" from O'Reilly press a couple of weeks ago. (592 pages). "Beautiful Code" is a collection of essays that attempt to capture code at it's most elegant. They subtitle being "Leading Programmers Explain How They Think".

I never really thought of code as potentially beautiful so the title caught my attention right away. What kind of code would they present to be called beautiful? While there were some interesting ideas presented there were no bright flashes of beauty.

The subtitle was more misleading. Some of the essays did attempt to explain what the author was thinking when creating a particular design. The majority of the essays, however, skipped this interesting conceit entirely. Many of the essays could have used some insight into the programmer's thought process because the code in and of itself wasn't all that interesting.

I don't want to give the impression that I didn't like this book. On the contrary, "Beautiful Code" was a very novel approach to what can be a very dry subject. Many of the writers were able to inject a sense of purpose and passion into their discussions that was refreshing. Too many times with a book about code authors spend all their time talking esoteric coding "magic".

The discussion on Google's use of the MapReduce algorithm was pretty cool. The problem of efficiently searching for words found in every known searchable webpage has always fascinated me. I knew it must be a parallel algorithm. What I didn't know was the algorithm used at Google was designed for general purpose computations. I always assumed Google wrote a special purpose system; optimized and targeted at search.

There was a topic on the design and implementation of the Linux kernel driver architecture. It was enlightening to see inheritance implemented in strict C. I knew it was possible but really hadn't given the idea much thought. After reading this topic, however, I see a very useful and extensible design.

One topic talked about a 'Spoonful of sewage'. The idea being you only have to introduce a little bit of garbage to ruin something completely; like a spoonful of sewage added to a barrel of wine. The theme concerned finding a bug deep in the guts of the Solaris OS. I really appreciated the insights not only into the code but the thoughts and hard learned lessons behind the code. In the end it took a very small change to introduce a very nasty and hard to debug problem into the system.

The languages used in each topic varied; from standard C++ and Java, scripting languages like Perl and Ruby, and functional languages like Lisp and Erlang. This variety of languages was refreshing and really points to the old saw about selecting the appropriate language for the job at hand.

All in all I did enjoy this book. The one problem I had with the book was consistency. The editor gave each author a lot of flexibility to discuss whatever they wanted to write about. This left some topics that were really insightful, some were light on details and heavy on 'concepts', while others seems simply self aggrandizing. From what I recall there were two chapters dedicated to basically the same technology. I wish each topic was more focused on the author's thought processes and presented more lessons learned in the trenches.

You might have to pick your diamonds from the coal with this book. In the end I found "Beautiful Code" a worthy read.
Oracle select for update cursor not updating?

I created an Oracle stored procedure the other day that used a 'select for update' cursor to update some information in a staging table. None of the update statements seemed to work. I thought I had the syntax wrong, etc. After spending some time just staring at the code I asked a coworker to take a quick look. We both sat down to examine my code. Everything looked fine.


My procedure looked something like:

   1: create or update procedure my_procedure( mydata IN varchar2 )
   2: is
   3: begin
   4:    declare
   5:       cursor my_cur is select * from my_table
   6:       where my_value > 100 for update;
   7:       row_entry my_cur%ROWTYPE;
   8:    begin
   9:       -- open the cursor, fetch into row_entry, loop, etc.
  10:       -- update the MYDATA column
  11:       update my_table set MYDATA=mydata where current of my_cur;
  12:    end;
  13: end;

This looked ok to the both of us. Eventually we figured it out.

At line 11 I'm trying to assign the value of the 'in' parameter 'mydata' to the 'MYDATA' column of at the current location of the cursor. Note the name of both the column I'm trying to assign to and the name of the import parameter.

Oracle doesn't recognize that the right hand side of this assignment is my input parameter. It treats the right hand side as a column name instead. So in effect I'm assigning the value found at the current cursor location for column 'MYDATA' to the column 'MYDATA' -- basically a no-op.

Changing the name of the in parameter from 'mydata' to 'p_mydata' solved my problem.

I would have been nice if Oracle had at least warned me of this situation. It would have saved me a lot of time and frustration.
Thats oracle , sometimes we hit very funny error that we can imagine :)

Post a Comment

Last Modified: Saturday, 11-Jul-2009 09:22:22 EDT