So let's say that somewhere within my application, I have a class that creates a new object. This object contains a Release() method, and when my class is destroyed it calls the object's Release() from the class's destructor. All is good.
But let's say that I also have another class, which has a constructor that takes in that same object as a parameter. If we were to pass in the same pointer that was created from the first class, and we used an assignment operator to store the pointer in our second class, would it be best to not Release() the object from the second class, and instead leave that job up to the first class?
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class A {
public:
A();
~A()
{
m_obj->Release(); // Good practice.
}
Object* m_obj;
}
class B {
public:
B(Object* obj) { m_obj = obj; };
~B()
{
m_obj->Release(); // Bad practice?
}
Object* m_obj;
}
If you have two pointers to the same object, it is an error to release it twice. In fact the error has a name, if you've released it once, the other pointers are called Dangling References.
This problem has spawned a number of techniques.
auto_ptr maintains an owner for the pointer. The pointer is released when the owner dies.
shared_ptr maintains a reference count to determine how many times the pointer should be released before it actually is.
The nuclear option is garbage collection where the programmer leaves these things behind and the system uses reference counting internally to decide when to perform the actual release.
1) If all instances of B are guaranteed to die before A dies, it is okay to hold raw pointers (or reference_wrappers) in B and do nothing in the destructor. A may hold a unique_ptr<Object> and also do nothing in the destructor, if Object's own destructor is written to call Release(), or that unique_ptr is supplied with a deleter that does so.
2) If some B may outlive A, then it's a question of ownership:
2a) A is the owner, and Bs have to live with the idea that m_obj may be garbage (in this case, B should hold weak_ptr<Object>), then B's destructor does nothing.
2b) The A and every instance of B share ownership. In this case, the last B or A that dies has to release Object. In this case, both A and B should hold shared_ptr<Object>.
Yes, COM interfaces. Direct X 10, to be precise. But the thing is, "class B" is dependent upon the actual pointer to one of the interfaces passed by "class A"... So would CComPtr still be necessary? I don't think I'd need to add an extra reference, not when I need to collect the actual info from the original ref.
In this specific case, I think just keeping a copy of the original pointer would work better. But the issue still remains, how to release everything? Currently if I delete class A, the obj pointer will be released (and set to NULL). So does this mean there will be a memory-related issue when class B is deleted? Or will it even be safe to delete? Should I check in class B's destructor if the object is NULL, and release it if it isn't?
I don't understand very much your setup, but it is really up to you. COM rules state that you usually AddRef() whenever you duplicate the pointer, but it is OK if you don't so long you know what you are doing. So if you think your instance of B is tightly controlled and administered by A, you can probably do without the extra AddRef()/Release() pair.