October 10th, 2022

On the overloading of the address-of operator & in smart pointer classes

Many smart pointer classes overload the address-of operator & to give you access to the inner raw pointer.

Unfortunately, they disagree on what happens to the object being managed by the smart pointer before you get its raw address.

Library Existing contents
_com_ptr_t Released
ATL (CComPtr) Must be empty
(will assert in Debug)
MFC (IPTR) Released
WRL (ComPtr) Released
wil (com_ptr) Released
C++/WinRT (com_ptr) N/A

C++/WinRT avoids the confusion by simply not having an overloaded operator& at all! Not having an overloaded operator& also makes it easier to take the address of the smart pointer itself. The put() method Releases any managed COM pointer and then returns the address of the raw pointer.

So let’s finish the table. Let’s say that sp is the name of a variable of the corresponding smart pointer type.

Library Release Don’t release Assumes empty
_com_ptr_t &sp &sp.GetInterfacePtr()  
ATL (CComPtr)   &sp.p &sp
MFC (IPTR) &sp    
WRL (ComPtr) &sp
p.ReleaseAndGetAddressOf()
p.GetAddressOf()  
wil (com_ptr) &sp
sp.put()
sp.addressof()  
C++/WinRT (com_ptr) sp.put()    

Bonus chatter: The possibility of an overloaded operator& is one of those special cases you tend to forget about when writing template library code.¹ In general, it’s not safe to use the & operator to get the address of an object of unknown type, because the operator might be overloaded. You have to use std::addressof.

¹ Hey, at least it’s not an overloaded comma operator. That thing is nasty.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Michael EnsMicrosoft employee

    I recall a time this caused great sadness. There was a custom smart pointer type that had the release-on-& behaviour. It was accessed in a fashion like this:

    spLinkedList->Next(&spLinkedList);

    Which, if it's not obvious how that breaks, can be thought of as similar to a C function with the variable left of the "->" being passed as a magic first parameter 'this' pointer:

    CPlusPlusNameMangling_Next(spLinkedList, &spLinkedList)

    Order of evaluation of arguments is undefined in C++. So there's two possible results. In our original compiler, it evaluated left-to-right. That meant we passed the variable as the this pointer, then we released...

    Read more
    • Dmitry · Edited

      Isn’t null-pointer dereferencing a case of UB on C++? Is AV really guaranteed, at least in the expected order? I remember Raymond’s articles on UB discussing that.

    • Neil Rashbrook · Edited

      Wouldn’t something like spLinkedList->Next(spLinkedList.put()); have the same issue?

      • Raymond ChenMicrosoft employee Author

        The hope is that the explicit call to put() is a clue that “Hey, I’m arrowing through an object and mutating it at the same time. That doesn’t seem right.” On the other hand, people don’t think of the & operator as a mutating operator.