jeudi 5 février 2015

C++ Smart Pointers and pointer-to-pointer output API's. Templated "wrapper"

In many API's especially C and COM-like API's, factory functions will create objects and store them in a caller provided location using a pointer to pointer. This is not directly compatible with std::unique_ptr, std::shared_ptr, and others following the same style (e.g. for COM or other intrusive reference counting schemes).



void myApiFactory(int x, Foo **out);

std::unique_ptr<Foo> myFoo;
myApiFactory(33, &myFoo);//not possible

//works, but bit of a pain, especially with API's that have lots of such things
Foo *tmp = nullptr;
myApiFactory(33, &tmp);
myFoo.reset(tmp);

//What I'm looking for
myApiFactory(33, outPtr(myFoo));


Implementation I am thinking of



/**@brief Type created and returned by outPtr(T &smartPtr)*/
template<class T>
class OutPtr
{
public:
typedef typename T::pointer pointer;
/**Constructor for outPtr*/
explicit OutPtr(T &smartPtr)
: smartPtr(&smartPtr)
, ptr(NULL)
{}
/**Move constructor for outPtr return*/
OutPtr(OutPtr<T> &&mv)
: smartPtr(mv.smartPtr)
, ptr(mv.ptr)
{
mv.smartPtr = NULL;
mv.ptr = NULL;
}

/**Destructor that stores the pointer set to the pointer to pointer in the
* provided smart pointer.
*/
~OutPtr()
{
if (smartPtr)
smartPtr->reset(ptr);
}

/**Implicit conversion to give the pointer to pointer to the function being
* called.
*/
operator pointer* ()
{
assert(ptr == NULL);
return &ptr;
}
private:
T* smartPtr;
pointer ptr;
//Should not be used, cause a compile error
OutPtr(const OutPtr&);
OutPtr& operator = (const OutPtr&);
OutPtr& operator = (OutPtr&&);
};


/**Provides a safe means to store an output pointer directly into an
* std::unique_ptr or similar smart pointer. The only requirement
* is that there is a pointer typedef, and a reset method that accepts a
* pointer of that type.
*
* void someFunction(int a, int b, Foo **out);
*
* std::unique_ptr<Foo,MyDeleter> foo;
* someFunction(4, 23, outPtr(foo));
*/
template<class T>
OutPtr<T> outPtr(T &ptr)
{
return OutPtr<T>(ptr);
}

Aucun commentaire:

Enregistrer un commentaire