April 2015

Volume 30 Number 4


Windows with C++ - Visual C++ 2015 Brings Modern C++ to Legacy Code

By Kenny Kerr | April 2015

Kenny KerrSystems programming with Windows relies heavily on opaque handles that represent objects hidden behind C-style APIs. Unless you’re programming at a fairly high level, chances are you’ll be in the business of managing handles of various kinds. The concept of a handle exists in many libraries and platforms and is certainly not unique to the Windows OS. I first wrote about a smart handle class template back in 2011 (msdn.microsoft.com/ magazine/hh288076) when Visual C++ started introducing some initial C++11 language features. Visual C++ 2010 made it possible to write convenient and semantically correct handle wrappers, but its support for C++11 was minimal and a lot of effort was still required to write such a class correctly. With the introduction of Visual C++ 2015 this year, I thought I’d revisit this topic and share some more ideas about how to use modern C++ to liven up some old C-style libraries.

The best libraries don’t allocate any resources and, thus, require minimal wrapping. My favorite example is the Windows slim reader/writer (SRW) lock. Here’s all it takes to create and initialize an SRW lock that’s ready to use:

SRWLOCK lock = {};

The SRW lock structure contains just a single void * pointer and there’s nothing to clean up! It must be initialized prior to use and the only limitation is that it can’t be moved or copied. Obviously, any modernization has more to do with exception safety while the lock is held, rather than resource management. Still, modern C++ can help to ensure these simple requirements are met. First, I can use the ability to initialize non-static data members where they’re declared to prepare the SRW lock for use:

class Lock
{
  SRWLOCK m_lock = {};
};

That takes care of initialization, but the lock can still be copied and moved. For that I need to delete the default copy constructor and copy assignment operator:

class Lock
{
  SRWLOCK m_lock = {};
public:
  Lock(Lock const &) = delete;
  Lock & operator=(Lock const &) = delete;
};

This prevents both copies and moves. Declaring these in the public part of the class tends to produce better compiler error messages. Of course, now I need to provide a default constructor because one is no longer assumed:

class Lock
{
  SRWLOCK m_lock = {};
public:
  Lock() noexcept = default;
  Lock(Lock const &) = delete;
  Lock & operator=(Lock const &) = delete;
};

Despite the fact that I haven’t written any code, per se—the compiler is generating everything for me—I can now create a lock quite simply:

Lock lock;

The compiler will forbid any attempts to copy or move the lock:

Lock lock2 = lock; // Error: no copy!
Lock lock3 = std::move(lock); // Error: no move!

I can then simply add methods for acquiring and releasing the lock in various ways. The SRW lock, as its name suggests, provides both shared reader and exclusive writer locking semantics. Figure 1 provides a minimal set of methods for simple exclusive locking.

Figure 1 A Simple and Efficient SRW Lock

class Lock
{
  SRWLOCK m_lock = {};
public:
  Lock() noexcept = default;
  Lock(Lock const &) = delete;
  Lock & operator=(Lock const &) = delete;
  void Enter() noexcept
  {
    AcquireSRWLockExclusive(&m_lock);
  }
  void Exit() noexcept
  {
    ReleaseSRWLockExclusive(&m_lock);
  }
};

Check out “The Evolution of Synchronization in Windows and C++” (msdn.microsoft.com/magazine/jj721588) for more information on the magic behind this incredible little locking primitive. All that remains is to provide a bit of exception safety around lock ownership. I certainly wouldn’t want to write something like this:

lock.Enter();
// Protected code
lock.Exit();

Instead, I’d like a lock guard to take care of acquiring and releasing the lock for a given scope:

Lock lock;
{
  LockGuard guard(lock);
  // Protected code
}

Such a lock guard can simply hold onto a reference to the under­lying lock:

class LockGuard
{
  Lock & m_lock;
};

Like the Lock class itself, it’s best that the guard class not allow copies or moves, either:

class LockGuard
{
  Lock & m_lock;
public:
  LockGuard(LockGuard const &) = delete;
  LockGuard & operator=(LockGuard const &) = delete;
};

All that remains is for a constructor to enter the lock and the destructor to exit the lock. Figure 2 wraps up that example.

Figure 2 A Simple Lock Guard

class LockGuard
{
  Lock & m_lock;
public:
  LockGuard(LockGuard const &) = delete;
  LockGuard & operator=(LockGuard const &) = delete;
  explicit LockGuard(Lock & lock) noexcept :
    m_lock(lock)
  {
    m_lock.Enter();
  }
  ~LockGuard() noexcept
  {
    m_lock.Exit();
  }
};

To be fair, the Windows SRW lock is quite a unique little gem and most libraries will require a bit of storage or some kind of resource that must be explicitly managed. I’ve already shown how best to manage COM interface pointers in “COM Smart Pointers Revisited” (msdn.microsoft.com/magazine/dn904668), so now I’ll focus on the more general case of opaque handles. As I wrote previ­ously, a handle class template must provide a way to parameterize not only the type of the handle, but also the way in which the handle is closed, and even what exactly represents an invalid handle. Not all libraries use a null or zero value to represent invalid handles. My original handle class template assumed the caller would provide a handle traits class that gives the necessary semantics and type information. Having written many, many traits classes in the intervening years, I came to realize that the vast majority of these follow a similar pattern. And, as any C++ developer will tell you, patterns are what templates are adept at describing. So, along with a handle class template, I now employ a handle traits class template. The handle traits class template isn’t required, but does simplify most definitions. Here’s its definition:

template <typename T>
struct HandleTraits
{
  using Type = T;
  static Type Invalid() noexcept
  {
    return nullptr;
  }
  // Static void Close(Type value) noexcept;
};

Notice what the HandleTraits class template provides and what it specifically does not provide. I’ve written so many Invalid methods that returned nullptr values that this seemed like an obvious default. On the other hand, each concrete traits class must provide its own Close method for obvious reasons. The comment lives on merely as a pattern to follow. The type alias is likewise optional and is merely a convenience for defining my own traits classes derived from this template. Therefore, I can define a traits class for file handles returned by the Windows CreateFile function, as shown here:

struct FileTraits
{
  static HANDLE Invalid() noexcept
  {
    return INVALID_HANDLE_VALUE;
  }
  static void Close(HANDLE value) noexcept
  {
    VERIFY(CloseHandle(value));
  }
};

The CreateFile function returns the INVALID_HANDLE_VALUE value if the function fails. Otherwise, the resulting handle must be closed using the CloseHandle function. This is admittedly unusual. The Windows CreateThreadpoolWork function returns a PTP_WORK handle to represent the work object. This is just an opaque pointer and a nullptr value is naturally returned on failure. As a result, a traits class for work objects can take advantage of the HandleTraits class template, which saves me a bit of typing:

struct ThreadPoolWorkTraits : HandleTraits<PTP_WORK>
{
  static void Close(Type value) noexcept
  {
    CloseThreadpoolWork(value);
  }
};

So what does the actual Handle class template look like? Well, it can simply rely on the given traits class, infer the type of the handle and call the Close method, as needed. The inference takes the form of a decltype expression to determine the type of the handle:

template <typename Traits>
class Handle
{
  using Type = decltype(Traits::Invalid());
  Type m_value;
};

This approach keeps the author of the traits class from having to include a type alias or typedef to provide the type explicitly and redundantly. Closing the handle is the first order of business and a safe Close helper method is tucked into the private part of the Handle class template:

void Close() noexcept
{
  if (*this) // operator bool
  {
    Traits::Close(m_value);
  }
}

This Close method relies on an explicit Boolean operator to determine whether the handle needs to be closed before calling the traits class to actually perform the operation. The public explicit Boolean operator is another improvement over my handle class template from 2011 in that it can simply be implemented as an explicit conversion operator:

explicit operator bool() const noexcept
{
  return m_value != Traits::Invalid();
}

This solves all kinds of problems and is certainly a lot easier to define than traditional approaches that implement a Boolean-like operator while avoiding the dreaded implicit conversions the compiler would otherwise permit. Another language improvement, which I’ve already made use of in this article, is the ability to explicitly delete special members, and I’ll do that now for the copy constructor and copy assignment operator:

Handle(Handle const &) = delete;
Handle & operator=(Handle const &) = delete;

A default constructor can rely on the traits class to initialize the handle in a predictable manner:

explicit Handle(Type value = Traits::Invalid()) noexcept :
  m_value(value)
{}

And the destructor can simply rely on the Close helper:

~Handle() noexcept
{
  Close();
}

So, copies aren’t permitted, but apart from the SRW lock, I can’t think of a handle resource that doesn’t permit moving its handle around in memory. The ability to move handles is tremendously convenient. Moving handles involves two individual operations that I might refer to as detach and attach, or perhaps detach and reset. Detach involves releasing the ownership of the handle to the caller:

Type Detach() noexcept
{
  Type value = m_value;
  m_value = Traits::Invalid();
  return value;
}

The handle value is returned to the caller and the handle object’s copy is invalidated to ensure that its destructor doesn’t call the Close method provided by the traits class. The complementary attach or reset operation involves closing any existing handle and then assuming ownership of a new handle value:

bool Reset(Type value = Traits::Invalid()) noexcept
{
  Close();
  m_value = value;
  return static_cast<bool>(*this);
}

The Reset method defaults to the handle’s invalid value and becomes a simple way to close a handle prematurely. It also returns the result of the explicit Boolean operator as a convenience. I found myself writing the following pattern quite regularly:

work.Reset(CreateThreadpoolWork( ... ));
if (work)
{
  // Work object created successfully
}

Here, I’m relying on the explicit Boolean operator to check the validity of the handle after the fact. Being able to condense this into a single expression can be quite convenient:

if (work.Reset(CreateThreadpoolWork( ... )))
{
  // Work object created successfully
}

Now that I have this handshake in place I can implement the move operations quite simply, beginning with the move constructor:

Handle(Handle && other) noexcept :
  m_value(other.Detach())
{}

The Detach method is called on the rvalue reference and the newly constructed Handle effectively steals ownership away from the other Handle object. The move assignment operator is only slightly more complicated:

Handle & operator=(Handle && other) noexcept
{
  if (this != &other)
  {
    Reset(other.Detach());
  }
  return *this;
}

An identity check is first performed to avoid attaching a closed handle. The underlying Reset method doesn’t bother to perform this kind of check as that would involve two additional branches for every move assignment. One is prudent. Two is redundant. Of course, move semantics are grand, but swap semantics are even better, especially if you’ll be storing handles in standard containers:

void Swap(Handle<Traits> & other) noexcept
{
  Type temp = m_value;
  m_value = other.m_value;
  other.m_value = temp;
}

Naturally, a non-member and lowercase swap function is required for genericity:

template <typename Traits>
void swap(Handle<Traits> & left, Handle<Traits> & right) noexcept
{
  left.Swap(right);
}

The final touches to the Handle class template come in the form of a pair of Get and Set methods. Get is obvious:

Type Get() const noexcept
{
  return m_value;
}

It simply returns the underlying handle value, which may be needed to pass to various library functions. The Set is perhaps less obvious:

Type * Set() noexcept
{
  ASSERT(!*this);
  return &m_value;
}

This is an indirect set operation. The assertion underscores this fact. I have in the past called this GetAddressOf, but that name disguises or contradicts its true purpose. Such an indirect set operation is needed in cases where the library returns a handle as an out parameter. The WindowsCreateString function is just one example out of many:

HSTRING string = nullptr;
HRESULT hr = WindowsCreateString( ... , &string);

I could call WindowsCreateString in this way and then attach the resulting handle to a Handle object, or I can simply use the Set method to assume ownership directly:

Handle<StringTraits> string;
HRESULT hr = WindowsCreateString( ... , string.Set());

That’s much more reliable and clearly states the direction in which the data is flowing. The Handle class template also provides the usual comparison operators, but thanks to the language’s support for explicit conversion operators, these are no longer necessary for avoiding implicit conversion. They just come in handy, but I’ll leave that for you to explore. The Handle class template is just another example from Modern C++ for the Windows Runtime (moderncpp.com).


Kenny Kerr is a computer programmer based in Canada, as well as an author for Pluralsight and a Microsoft MVP. He blogs at kennykerr.ca and you can follow him on Twitter at twitter.com/kennykerr.