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).

class Base {
void DecRef {
m_count--;
if (!m_count) delete this;
}
int m_count;
}

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

class Derived : public Base {
void DecRef() {
...;
}
int m_count;
}

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:

SmartPointer sp1 = new Derived();
// m_count = 1
// later...

SmartPointer sp3 = sp1; // Base::m_count=1, Derived::m_count=1
// sp3 falls out of scope, Base::m_count=0, Derived::m_count=1
// Whops, Base::m_count went to zero and the original object was deleted.
// Anyone using sp1 has a null pointer / deleted variable to work with instead
// 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.:

Tagged with: , , ,
Posted in Uncategorized
Design a site like this with WordPress.com
Get started