Riffing on Raymond – incrementing the reference count on a smart pointer


Last Friday, Raymond Chen blogged about how to use a function that released one of its inputs with various smart pointer classes.

He made two suggestions, and I offered a third:

  1. (Raymond) tell the smart pointer class to release ownership to the function
  2. (Raymond) use a different function that doesn't release the input
  3. (Me) take an explicit reference on the function's behalf

Raymond suggested that I should actually try my suggestion. So I did.

For each of the four smart pointer types, I tried four different ways to add a reference. Here are the results:

Smart pointer type .AddRef() ->AddRef() Cast to IUnknown * Get underlying pointer
Microsoft::WRL::ComPtr Compile error Compile error Compile error .Get()
ATL::CComPtr Compile error Compile error OK .p
_com_ptr_t OK OK OK .GetInterfacePtr()
std::unique_ptr Compile error OK Compile error .get()

Here's the code I used.

Comments (4)

  1. IInspectable says:

    Suggestion 3.) is pretty much backwards. Ignoring the fact, that it sometimes doesn't compile, it also violently ignores logic:

    Incrementing the ref count prior to calling CoGetInterfaceAndReleaseStream necessitates, that you are aware of the fact, that both the function and the smart pointer will call Release() on the interface. So you already solved the hard part: Identifying a potential error.

    And then you stumble so miserably on the easy part, simply moving forward, in a straight line, calling the operation on the smart pointer that was explicitly implemented to be called whenever you transfer ownership.

    I'll just assume you were only half serious, or haven't had your coffee, when you came up with this convoluted solution, that simply ain't.

  2. I agree that in most cases using .Detach() is appropriate. But what if you want to continue to use the object after the consuming function returns?

    GetThingy(&sp);

    UseThingyEatsInput(sp.Detach());

    UseThingy(sp); // gets nullptr!

    I suppose the .Detach() solution can still be used with a temporary:

    UseThingyEatsInput(SmartPointerType(p).Detach());

    Effectively this becomes a .GetAddRefdPointer().

  3. IInspectable says:

    Well, uhm… if you want to continue to use the object, then don't throw it away before you're done with it. In other words, call CoUnmarshalInterface instead of CoGetInterfaceAndReleaseStream (Raymond's suggestion 2).

  4. Sure. You're suggesting that 2. is better than 3. I agree.

    The problem statement is "I have a smart pointer, and I want to hand it to a function that consumes its input. What are my options?"

    The solutions are:

    0. Use a dumb pointer

    1. Tell the smart pointer to transfer its reference to the function

    2. Use a different function that doesn't consume the reference

    3. Take an explicit reference on the function's behalf

    Which solution you choose is up to you, and will depend on your needs.

    The benefits of 3 are (a) it preserves the pointer, and (b) it is easy for a code reviewer to see the AddRef and …AndRelease next to each other and figure out that the reference count is preserved.

Skip to main content