9

I've been using std::unique_ptr to store some COM resources, and provided a custom deleter function. However, many of the COM functions want pointer-to-pointer. Right now, I'm using the implementation detail of _Myptr, in my compiler. Is it going to break unique_ptr to be accessing this data member directly, or should I store a gajillion temporary pointers to construct unique_ptr rvalues from?

15
  • 1
    Why don't you use ATL::CComPtr or _com_ptr_t? Commented Dec 20, 2010 at 6:59
  • 1
    @sharptooth: My application only holds one reference. There's no need to go reference counting for my one reference. Commented Feb 17, 2011 at 13:26
  • 1
    @DeadMG: No problem, but some other COM object you're not aware of could have got hold on the object and wish to share ownership. You just can't combine "I think I'm the only one who holds a pointer" with COM objects since they are all designed to support reference counting. Commented Feb 17, 2011 at 13:51
  • 1
    My point is even if you don't need reference counting you'll have to use it. Commented Feb 17, 2011 at 13:54
  • 2
    @sharptooth: You're misreading me. I only hold one reference. The other references are still all counted. And it's just COM objects- working with DirectX. Commented Feb 17, 2011 at 14:13

4 Answers 4

6

COM objects are reference-countable by their nature, so you shouldn't use anything except reference-counting smart pointers like ATL::CComPtr or _com_ptr_t even if it seems inappropriate for your usecase (I fully understand your concerns, I just think you assign too much weight to them). Both classes are designed to be used in all valid scenarios that arise when COM objects are used, including obtaining the pointer-to-pointer. Yes, that's a bit too much functionality, but if you don't expect any specific negative consequences you can't tolerate you should just use those classes - they are designed exactly for this purpose.

Sign up to request clarification or add additional context in comments.

1 Comment

This. The COM objects are reference counted anyway, so whether you like it or not, anything you do will be a redundant wrapper on top of that. boost::unique_ptr is not designed for this so any attempt to shoe-horn it in will add needless complexity and chance for error. CComPtr has no overhead. Just use that.
4

I've had to tackle the same problem not too long ago, and I came up with two different solutions:

The first was a simple wrapper that encapsulated a 'writeable' pointer and could be std::moved into my smart pointer. This is just a little more convenient that using the temp pointers you are mentioning, since you cannot define the type directly at the call-site.

Therefore, I didn't stick with that. So what I did was a Retrieve helper-function that would get the COM function and return my smart-pointer (and do all the temporary pointer stuff internally). Now this trivially works with free-functions that only have a single T** parameter. If you want to use this on something more complex, you can just pass in the call via std::bind and only leave the pointer-to-be-returned free.

I know that this is not directly what you're asking, but I think it's a neat solution to the problem you're having.

As a side note, I'd prefer boost's intrusive_ptr instead of std::unique_ptr, but that's a matter of taste, as always.

Edit: Here's some sample code that's transferred from my version using boost::intrusive_ptr (so it might not work out-of-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 like this:

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 the unique_ptr instead of taking it by reference. The functor that bind generates should have signature typedefs to derive the pointer type. You can then throw an exception if you get a bad HRESULT.

Comments

1

C++0x smart pointers have a portable way to get at the raw pointer container .get() or release it entirely with .release(). You could also always use &(*ptr) but that is less idiomatic.

If you want to use smart pointers to manage the lifetime of an object, but still need raw pointers to use a library which doesn't support smart pointers (including standard c library) you can use those functions to most conveniently get at the raw pointers.

Remember, you still need to keep the smart pointer around for the duration you want the object to live (so be aware of its lifetime).

Something like:

call_com_function( &my_uniq_ptr.get() ); // will work fine
return &my_localscope_uniq_ptr.get();    // will not
return &my_member_uniq_ptr.get();        // might, if *this will be around for the duration, etc..

Note: this is just a general answer to your question. How to best use COM is a separate issue and sharptooth may very well be correct.

2 Comments

You've completely misread the question. I need a pointer to the internal pointer in unique_ptr, not just the value.
unique_ptr doesn't provide a way to directly access the internal pointer because it would be dramatically unsafe to do so. The point of smart pointers is to be safe.
-1

Use a helper function like this.

template< class T >
T*& getPointerRef ( std::unique_ptr<T> & ptr )
{
    struct Twin : public std::unique_ptr<T>::_Mybase {};
    Twin * twin = (Twin*)( &ptr );
    return twin->_Myptr;
}

check the implementation

int wmain ( int argc, wchar_t argv[] )
{   
    std::unique_ptr<char> charPtr ( new char[25] );
    delete getPointerRef(charPtr);
    getPointerRef(charPtr) = 0;

    return charPtr.get() != 0;
}

1 Comment

I just noticed that you delete what you new[].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.