Std :: unique_ptr and pointer to pointer

I use std :: unique_ptr to store some COM resources and provide a custom delete function. However, many of the COM functions require a pointer to a pointer. Right now, I'm using the _Myptr implementation detail in my compiler. Is it going to break unique_ptr into direct access to this data element or do I need to store gajillion temporary pointers to create unique_ptr rvalues โ€‹โ€‹from?

+8
c ++ 11 com
source share
4 answers

COM objects are referenced in nature, so you should not use anything other than reference to counts such as ATL::CComPtr or _com_ptr_t , even if this seems inappropriate for your use (I fully understand your problems, I just think that you give them too much weight). Both classes are intended for use in all valid scenarios that arise when using COM objects, including getting a pointer to a pointer. Yes, this is too much functionality, but if you do not expect any specific negative consequences that you cannot tolerate, you should simply use these classes - they are designed for this very purpose.

+6
source share

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 .

+4
source share

C ++ 0x smart pointers have a portable way to get to the raw container container .get () or completely release it .release (). You can also always use & (* ptr), but this is less idiomatic.

If you want to use smart pointers to control the lifetime of an object, but still need raw pointers to use a library that does not support smart pointers (including the standard c library), you can use these functions for the most convenient access to source pointers.

Remember that you still need to keep a smart pointer for the duration that you want the object to live (so keep in mind 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 best to use COM is a separate issue, and sharptooth may very well be right.

+1
source share

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 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; } 
-one
source share

Source: https://habr.com/ru/post/650296/


All Articles