I had to solve the same problem not so long ago, and I came up with two different solutions:
The first was a simple wrapper that encapsulated a โwritableโ pointer and could be std::move
d in my smart pointer. This is a little more convenient if you use the temp pointers that you mention, because you cannot determine the type directly on the call site site.
Therefore, I did not adhere to this. So what I did was a Retrieve
helper function that will receive a COM function and return my smart pointer (and will do all the temporary contents of the pointer inside). Now this works trivially with free functions that have only one T**
parameter. If you want to use this for something more complex, you can just pass the call through std::bind
and leave only a pointer exemption.
I know that this is not exactly what you are asking for, but I think it is a clear solution to the problem you are facing.
As a side note, I'd rather increase intrusive_ptr instead of std :: unique_ptr, but this is a matter of taste, as always.
Edit: Here is an example of code that was ported from my version using boost :: intrusive_ptr (so that it doesn't work due to the box with unique_ptr)
template <class T, class PtrType, class PtrDel> HRESULT retrieve(T func, std::unique_ptr<PtrType, PtrDel>& ptr) { ElementType* raw_ptr=nullptr; HRESULT result = func(&raw_ptr); ptr.reset(raw_ptr); return result; }
For example, it can be used as follows:
std::unique_ptr<IFileDialog, ComDeleter> FileDialog; using std::bind; using namespace std::placeholders; std::unique_ptr<IShellItem, ComDeleter> ShellItem; HRESULT status = retrieve(bind(&IFileDialog::GetResult, FileDialog, _1), ShellItem);
For bonus points, you can even let Retrieve
return unique_ptr instead of taking it by reference. The functor that bind
generates must have typedefs in order to get the type of the pointer. Then you can throw an exception if you get a bad HRESULT
.