Cast DirectX interfaces to IUnknown pointers - c++

Having quite a few interfaces in my code, I wanted to encapsulate repeating Release code in another method and not in a macro because this is C++ and I hate using macros. My initial attempt was to write a method such as
void SafeRelease(IUnknown **ppInterface) {
if(*ppInterface) {
(*ppInterface)->Release();
(*ppInterface) = nullptr;
}
}
however applying this method to a IDirect3DSurface9 * e.g. like SafeRelease(&mySurface) yields the error IDirect3DSurface9 ** is incompatible with IUnknown **.
What am I doing here wrong?
Is there a better approach (hopefully not using macros) to implement such a function?

Here's my method:
template <typename T> void SafeRelease(T*& ptr)
{
if(ptr)
{
ptr->Release();
ptr = nullptr;
}
}
Example usage:
IDirect3DDevice9 *pD3DDevice = NULL;
d3d->CreateDevice(..., &pD3DDevice);
SafeRelease(pD3DDevice);
You may inline this function if you want.

You could use a template:
template<class DXInterface>
void SafeRelease(DXInterface **ppInterface) {
if(*ppInterface) {
(*ppInterface)->Release();
(*ppInterface) = nullptr;
}
}
You could also use a std::unique_ptr or std::shared_ptr to automatically cleanup:
#include <memory>
#include <iostream>
struct Releaser {
template<class DXInterface>
void operator()(DXInterface *pInterface) const {
if(pInterface) {
pInterface->Release();
}
}
};
// For illustrative purposes only (supplied in DX9 headers)
struct IDirect3DSurface9 { void Release() { std::cout << "Released surface\n";} };
struct IDirect3DTexture9 { void Release() { std::cout << "Released texture\n";} };
void DX9CreateSurface( IDirect3DSurface9** surface )
{
*surface = new IDirect3DSurface9();
}
void DX9CreateTexture( IDirect3DTexture9** texture )
{
*texture = new IDirect3DTexture9();
}
// Your factory functions
IDirect3DSurface9* createSurface( /*init params go here*/ )
{
IDirect3DSurface9* surface;
DX9CreateSurface( &surface );
return surface;
}
IDirect3DTexture9* createTexture( /*init params go here*/ )
{
IDirect3DTexture9* texture;
DX9CreateTexture( &texture );
return texture;
}
int main()
{
typedef std::unique_ptr<IDirect3DSurface9, Releaser> SurfacePtr;
typedef std::unique_ptr<IDirect3DTexture9, Releaser> TexturePtr;
SurfacePtr surface( createSurface() );
TexturePtr texture( createTexture() );
// ... use surface and texture here
// Automatically released here when their lifetimes ends.
}
Note that they use the same Releaser, and note that a call to surface.reset() would also release the interface and would set the pointer inside the unique_ptr to null to boot. These two objects could be members of your class rather than objects in main().

What am I doing here wrong?
I just had the same question, also for COM SafeRelease. So here goes:
void SafeRelease(IUnknown **ppInterface)
...
IDirect3DSurface9 * mySurface = new ...
...
SafeRelease(&mySurface);
IDirect3DSurface9 *, by virtue of inheritance, can be cast to IUnknown *.
But, counterintuitively, IDirect3DSurface9 ** cannot be cast to IUnknown **.
If it were allowed, then inside your SafeRelease(IUnknown**) you could do the following:
// obtain a pointer to an instance of some random subinterface of IUnknown
*ppInterface = pMyRamdomComInterfacePointer;
And thus we would have stored a pointer to some random IUnknown derivative in a pointer to IDirect3DSurface9. That would violate the C++ type system. Which is why casting any other type but T** to T** is not allowed. In other words, a variable of type T** can only be assigned a ppT (a value of type T**) and not a ppSomeSubytpeOfT.
Compare this one: How come a pointer to a derived class cannot be passed to a function expecting a reference to a pointer to the base class? And this one: Casting double pointers of base classes.
For COM SafeRelease, either a template (as suggested here) or a macro will do.

Related

When should we use a custom deleter instead of the default deleter in a unique_ptr?

I couldn't understand, if there is already a default deleter in unique_ptr, then what is the need of using a custom deleter?
Could anyone explain this by giving a simple example?
I use custom deletes to quickly wrap C-API, for example to help me with OpenSSL:
namespace helper {
template<typename T>
struct Deleter;
template<>
struct Deleter<::BIO>
{
void operator()(::BIO* p) const
{
// result used during debugging
[[maybe_unused]] auto result = BIO_free(p);
}
};
template<>
struct Deleter<::X509>
{
void operator()(::X509* p) const
{
X509_free(p);
}
};
template<>
struct Deleter<::PKCS12>
{
void operator()(::PKCS12* p) const
{
PKCS12_free(p);
}
};
template<>
struct Deleter<::EVP_PKEY>
{
void operator()(::EVP_PKEY* p) const
{
EVP_PKEY_free(p);
}
};
template<>
struct Deleter<STACK_OF(X509)>
{
void operator()(STACK_OF(X509) * p) const
{
sk_X509_pop_free(p, X509_free);
}
};
template<>
struct Deleter<STACK_OF(GENERAL_NAME)>
{
void operator()(STACK_OF(GENERAL_NAME) * p) const
{
sk_GENERAL_NAME_free(p);
}
};
template<>
struct Deleter<GENERAL_NAME>
{
void operator()(GENERAL_NAME* p) const
{
GENERAL_NAME_free(p);
}
};
template<typename T, typename D = Deleter<T>>
std::unique_ptr<T, D> wrapUnique(T* p, D deleter = {})
{
return std::unique_ptr<T, D>{p, deleter};
}
}
And I use other helper functions to make use OpenSSL more C++sy.
This is especially handy when handling errors (since release of resources is painless in such case).
Here is an example of using std::unique_ptr to manage an old C style FILE* in RAII style.
The deleter will close the file automatically when the std::unique_ptr will attempt to release the managed resource.
This is useful e.g. if you have some legacy code using FILE* file(s) and you would like to avoid manually managing closing them.
#include <iostream>
#include <memory>
struct FileDeleter
{
void operator()(FILE* pFile)
{
if (pFile)
{
std::cout << "closing file ...\n";
fclose(pFile);
}
}
};
using FileUniquePtr = std::unique_ptr<FILE, FileDeleter>;
int main()
{
{
// Getting a FILE* from legacy code:
FILE* pFile = nullptr;
std::cout << "opening file ...\n";
auto err = fopen_s(&pFile, "aaa.txt", "r");
if (err != 0)
{
// Handle error ...
return -1;
}
// New C++ code:
FileUniquePtr filePtr{ pFile };
// Do something with the file via filePtr ...
} // Here filePtr goes out of scope and the deleter will be called and close the file automatically.
}
Output:
opening file ...
closing file ...
The default deleter is ok if doing delete over the pointer wrapped by unique_ptr is the correct thing to do to dispose of it. That is ok if your pointer comes from new, but it's not correct in many other situations.
A simple example is FILE *: a FILE * is a pointer that cannot be deleted with delete, but instead you have to use fclose on it. Using a custom deleter it's very easy to wrap it in a unique_ptr and let it take care of destruction/move/...:
namespace detail {
struct file_ptr_deleter {
void operator() (FILE *fp) {
if(fp) fclose(fp);
}
};
}
/// RAII-style wrapper for a FILE*
struct unique_c_file : std::unique_ptr<FILE, detail::file_ptr_deleter> {
using std::unique_ptr<FILE, detail::file_ptr_deleter>::unique_ptr;
operator FILE *() { return get(); }
};
(in this case I even inherited from std::unique_ptr to ease the use of unique_c_file directly in C APIs).
Other, possibly more common cases, are if you have memory that comes from libraries, that provide their own function to delete it; for example, you may use BSD sockets, where getaddrinfo provides you an addrinfo * that must be freed using freeaddrinfo; even in this case, it's easy to create a smart pointer for that:
namespace detail {
struct addrinfo_deleter {
void operator()(addrinfo *elem) {
if(elem) freeaddrinfo(elem);
}
};
}
/// unique_ptr to handle an %addrinfo linked list provided by %getaddrinfo
typedef std::unique_ptr<addrinfo, detail::addrinfo_deleter> addrinfo_ptr;
Similarly in Win32 programming where many APIs provide you memory that has been allocated with LocalAlloc and thus must be freed with LocalFree:
// Custom deleter (for unique_ptr) using Win32 LocalFree
struct LocalFree_deleter { void operator()(void *ptr) { LocalFree(ptr); } };
// ...
std::unique_ptr<LPWSTR[], LocalFree_deleter> argvw(CommandLineToArgvW(cmdline_u16, &argc));
You can even go a step further, and work with stuff that aren't even pointers, but opaque "handles": again in Win32 this is quite common, and there are even different types of handles require different closing functions; even in this case, unique_ptr and custom deleters to the rescue:
template<decltype(CloseHandle) ch_fn = CloseHandle>
struct handle_deleter {
typedef HANDLE pointer;
void operator()(HANDLE obj) {
if(obj != NULL && obj != INVALID_HANDLE_VALUE) ch_fn(obj);
}
};
using unique_handle = std::unique_ptr<HANDLE, handle_deleter<>>;
using unique_find_handle = std::unique_ptr<HANDLE, handle_deleter<FindClose>>;
notice that here handle_deleter provided a typedef HANDLE pointer: this typedef is used by unique_ptr as the type that it stores in its bowels, returns in get() & co.

Reducing number of argumnets passed to function

I have a class named Window, and a big bunch of functions which need an instance of Window to work. So I have passed Window* win as an argument to each of these functions, but this approach creates a copy of Window* every time it is called and also, it seems kinda unnecessary passing the argument to each function. I have tried passing const Window* but that won't work either because the functions inside Window don't have a const version. I thought that using std:::shared_ptr and std::weak_ptr would help, but I still haven't figured it out correctly. Here's my current code:
// Window.h
class Window
{
public:
// some getters/setters and other functions
private:
// members are here
};
// on another file
int func1(Window* win /*I want to remove this */, ...) {
// use win and other parameters
}
And here's the smart pointers approach.
// class Window as declared above
// file.h
namespace space
{
struct context;
context* make_context(std::shared_ptr<Window> const& win); // const& to avoid copy
void destroy_context(context* ctx);
int func1(...); // note that ... is used to show some params whose type isn't important for the question.
}
// some other functions
// file.cpp
namespace space
{
struct context
{
std::weak_ptr<Window> target;
};
context* make_context(std::shared_ptr<Window> const& win) // const& to avoid copy
{
context* ctx = new context{};
ctx->target = win;
return ctx;
}
void destroy_context(context* ctx)
{
if(ctx != nullptr)
{
delete ctx;
ctx = nullptr;
}
}
int func1(...)
{
// use ... params
} // int func1(...)
} // namespace space
// main.cpp
int main(int, char**)
{
std::shared_ptr<Window> window{new Window{/*some arguments*/}};
auto ctx{space::make_context(window)};
int func1();
// some other code
delete ctx;
}
As explained already in the various comments, a parameter which is a pointer like Window* will never create a copy of the Window object. This is why a pointer is made for.
Before trying to figure out more complex tools like smart pointers, I suggest you first spend time understanding C++ fundamental. You should start by what is a value, what is a pointer, what is a reference.

Why do I get SIGSEGV error when use class function from pointer?

I'm new in C++ and runned into first trouble. I have a GameObject class in which I have to somehow store many components. Each component is a different class, so I can't just normally use vector. I decided to store a component's type and pointer to that object. The problem is, that when I get, return that component, and use a class function which uses it's member variables, I get SIGSEGV error(yeah, sounds confusing). However, if I normally use that class and that function, I don't get a SIGSEGV error.
GameObject.h:
enum ComponentType
{
MeshComponent // currently only one type
};
struct Component
{
ComponentType type;
void *pointer;
};
class GameObject
{
private:
std::vector<Component> components;
public:
void addComponent(ComponentType type);
template<typename T> T* getComponent()
{
for(std::vector<Component>::size_type i = 0; i != components.size(); i++)
{
// will need to somehow check T type later
if(components[i].type == MeshComponent)
{
return (Mesh*)&components[i].pointer;
}
}
Debug::Loge(GAMEOBJECT_TAG, "No %s component in %s gameobject!", componentTypeToString(MeshComponent).c_str(), name.c_str());
return 0;
}
}
GameObject.cpp:
void GameObject::addComponent(ComponentType type)
{
Component component;
component.type = type;
if(type == MeshComponent)
{
Mesh *mesh = new Mesh();
component.pointer = &mesh;
}
components.push_back(component);
}
Mesh.h
class Mesh
{
public:
Mesh *setMeshData(std::vector<GLfloat> data);
};
Mesh.cpp
Mesh *Mesh::setMeshData(vector<GLfloat> data)
{
meshData = data;
return this;
}
And finally this is how I use it:
GameObject object;
void somefunction()
{
object.addComponent(MeshComponent);
object.getComponent<Mesh>()->setMeshData(triangle_data); // SIGSEGV HERE!!
// if I use this one instead above - no sigsegv, everything is fine.
Mesh mesh;
mesh.setMeshData(triangle_data);
}
In here
Mesh *mesh = new Mesh();
component.pointer = &mesh;
you are taking the address of the pointer to mesh. Instead try
Mesh *mesh = new Mesh();
component.pointer = mesh;
because you defined your Component-pointer as void* pointer. If you wanted to take the address of Mesh* you would have to use void** pointer, but this is silly and would lead yet to another SIGSEGV.
if(components[i].type == MeshComponent)
{
return (Mesh*)&components[i].pointer;
}
Your return type is Mesh* but &components[i].pointer will be void**.
+ the above explanation by #bas.d

FunktionPointerArray in Singleton

I try to implement an array of function pointers in an singleton owning a thread.
In the thread function I get an error, telling me that a member has to be relative to an object. More in the commentline...
Header:
typedef struct{
int action;
HWND handle;
}JOB;
class Class{
public:
enum Action { 1,2 };
private:
JOB m_currentJob;
queue<JOB> Jobs;
static DWORD WINAPI ThreadFunction(LPVOID lpParam);
void (Class::*ftnptr[2])(JOB Job);
void Class::ftn1(JOB Job);
void Class::ftn2(JOB Job);
// Singleton pattern
public:
static Class* getInstance(){
if(sInstance == NULL)
sInstance = new Class();
return sInstance;
}
private:
Class(void);
~Class(void);
static Class* sInstance;
};
Body:
#include "Class.h"
Class* Class::sInstance = NULL;
Class::Class(){
this->ftnptr[0] = &Class::ftn1;
this->ftnptr[1] = &Class::ftn2;
}
DWORD WINAPI Class::AutoplayerThreadFunction(LPVOID lpParam)
{
Class *pParent = static_cast<Class*>(lpParam);
while(true){
(pParent->*ftnptr[pParent->m_currentJob.action])(pParent->m_currentJob);
/* The line above causes the compiler error. Curious to me is that
* neither "pParent->m_currentJob" nor "pParent->m_currentJob" cause
* any problems, although they are members too like the ftnptr array.
*/
}
}
void Class::ftn1(JOB Job){}
void Class::ftn2(JOB Job){}
A call via getInstance from the SingletonPattern doesnt make it any better.
Any suggestions?
ftnptr is a member of Class. However, you access it directly. That is, pParent->*ftnptr[...] means "access the member of pParent designated by the pointer ftnptr[...]", but it doesn't imply that ftnptr too is a member of pParent.
The correct code is (pParent->*(pParent->ftnptr[...]))(...). But I would recommend extracting the array index expression from that:
auto fnptr = pParent->ftnptr[...];
(pParent->*fnptr)(...);
I think it might be how you declare your array of pointer-to-member-functions. (Edit: This wasn't what was wrong. I'm keeping this answer up anyway, because typedefs for function pointers can really make code cleaner, so I think this is good advice.)
Try using a typedef:
typedef void (Class::*ftnptr)(JOB Job);
ftnptr[2] fn_ptrs;
Then use it like so:
Class::Class(){
this->fn_ptrs[0] = &Class::ftn1;
this->fn_ptrs[1] = &Class::ftn2;
}
DWORD WINAPI Class::AutoplayerThreadFunction(LPVOID lpParam)
{
Class *pParent = static_cast<Class*>(lpParam);
while(true){
(pParent->*(pParent->fn_ptrs[pParent->m_currentJob.action]))(pParent->m_currentJob);
/* The line above causes the compiler error. Curious to me is that
* neither "pParent->m_currentJob" nor "pParent->m_currentJob" cause
* any problems, although they are members too like the ftnptr array.
*/
}
}

Will a boost smart pointer help me?

i am using Xerces to do some xml writing.
here's a couple of lines extracted from my code:
DOMLSSerializer *serializer = ((DOMImplementationLS*)implementation)->createLSSerializer();
serializer->release();
Is there a boost smart pointer that i can use, so i can avoid calling serializer->release(); as it's not exception safe. The problem as i see it is that smart pointers can only call delete on your pointer object, could it be customised to call release?
thanks
Yes, smart pointers can call a custom "deleter" function object.
#include <iostream>
#include <tr1/memory>
struct Example {
void release() { std::cout << "Example::release() called\n"; }
};
struct ExampleDeleter {
void operator()(Example* e) { e->release(); }
};
int main()
{
{
std::tr1::shared_ptr<Example> p ( new Example, ExampleDeleter() );
}
std::cout << " see?\n";
}
(same for boost: see the shared_ptr(Y * p, D d); constructor.)
Yes, boost::shared_ptr can be used with a custom deleter functor (as shown by Cubbi) or a deleter function:
void my_deleter(DOMLSSerializer* s) {
s->release();
}
// ...
boost::shared_ptr<DOMLSSerializer> serializer(foo->createLSSerializer(), my_deleter);
Don't know why people write their own wrapper that way any more #Cubbi
As answered to make shared ptr not use delete
shared_ptr<DOMLSSerializer> serializer(
((DOMImplementationLS*)implementation)->createLSSerializer(),
std::mem_fun(&DOMLSSerializer::release) );
If you just need a tiny RAII class then you could write the helper class yourself. It's so small that it barely pulls its own weight (let alone justifies pulling in a library):
class DOMLSSerializerOwner {
public:
DOMLSSSerializerOwner( DOMLSSerializer *serializer ) : m_serializer( serializer ) { }
~DOMLSSerializerOwner() { m_serializer->release(); }
operator DOMLSSerializer*() { return m_serializer; }
private:
DOMLSSerializerOwner( const DOMLSSerializerOwner &other ); // disabled
void operator=( const DOMLSSerializerOwner &rhs ); // disabled
DOMLSSerializer *m_serializer;
};
Then you can make your code read:
void f()
{
DOMLSSerializerOwner serializer = ((DOMImplementationLS*)implementation)->createLSSerializer();
serializer->doThis();
serializer->doThis();
// Look Ma: no release() call; 'serializer' does it automatically when going out of scope
}