Clause 13: You must release the COM component in advance.
With smart pointers, you may not want to manually release or increase the reference count. In this case, please refer to the following functions:
View plaincopy to clipboardprint? Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
HRESULT hr = CoCreateInstance (
CLSID_HELLO
NULL,
CLSCTX_INPROC_SERVER,
IID_IHELLO,
(Void **) & spHello // resource leakage may occur here
);
Assert (SUCCEED (hr ));
SpHello-> DoOtherthing ();
}
Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
HRESULT hr = CoCreateInstance (
CLSID_HELLO
NULL,
CLSCTX_INPROC_SERVER,
IID_IHELLO,
(Void **) & spHello // resource leakage may occur here
);
Assert (SUCCEED (hr ));
SpHello-> DoOtherthing ();
}
You carefully checked the IID and pointer types and found no problem. In addition, the assert behind the CoCreateInstance gives you full confidence in his behavior.
But the problem is that spHello originally meant something. Will it release the reference count of the corresponding interface? The answer is undefined.
IP address fetch operations for spHello in non-null conditions are defined differently in different smart pointers. For CComPtr, he will initiate an assertion during debugging, And the RELEASE version will quietly let the resource leak. For _ com_ptr_t, whether in RELASE or DEBUG, it secretly releases crude oil resources without prompting the outside world about such dangerous operations.
Knowing the cause may be that you don't expect this dangerous operation to take the address character too much. You may have thought of the content described in "clause 11: creating resource sources and querying interfaces in a type-safe manner. Check whether there is a problem with the modified version below.
View plaincopy to clipboardprint? Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
SpHello. CoCreateInstance (CLSID_HELLO); // resource leakage may occur.
Assert (spHello );
SpHello-> DoOtherthing ();
}
Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
SpHello. CoCreateInstance (CLSID_HELLO); // resource leakage may occur.
Assert (spHello );
SpHello-> DoOtherthing ();
}
The problem still occurs, because CoCreateInstance still makes an asserted when spHello is not empty in the DEBUG version. Resources in RELEASE are leaked. For _ com_ptr_t, it is still quietly helping you release the resources first.
Therefore, the most secure response policy is: "You must release the COM component in advance, so don't think That smart pointers will help you complete it ".
View plaincopy to clipboardprint? Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
SpHello = NULL; // or spHello. Release (); Release resources in advance
SpHello. CoCreateInstance (CLSID_HELLO );
Assert (spHello );
SpHello-> DoOtherthing ();
}
Void InSomewhere (IHello * pHello)
{
CComPtr <IHello> spHello = pHello;
SpHello-> DoSomething ();
SpHello = NULL; // or spHello. Release (); Release resources in advance
SpHello. CoCreateInstance (CLSID_HELLO );
Assert (spHello );
SpHello-> DoOtherthing ();
}
OK. The problem is resolved.
In some cases, memory leakage occurs because you have not manually released the COM component. Suppose we have designed such a container to store smart pointers as follows:
View plaincopy to clipboardprint? Template <typename T>
Class MyStack
{
Public:
MyStack (int nCapacity ){
M_pArray = new T [nCapacity] ();
M_nCapacity = nCapacity;
M_nTop = 0;
};
~ MyStack (){
Delete [] m_pArray;
};
Void push (T Item ){
Assert (m_nTop <m_nCapacity );
M_pArray [m_nTop ++] = Item;
}
T pop (){
Assert (m_nTop> 0 );
Return m_pArray [-- m_nTop];
}
MyStack (const MyStack <T> & otherArray)
{
// Deep copy it
};
Private:
T * m_pArray;
Int m_nTop;
Int m_nCapacity;
};
Template <typename T>
Class MyStack
{
Public:
MyStack (int nCapacity ){
M_pArray = new T [nCapacity] ();
M_nCapacity = nCapacity;
M_nTop = 0;
};
~ MyStack (){
Delete [] m_pArray;
};
Void push (T Item ){
Assert (m_nTop <m_nCapacity );
M_pArray [m_nTop ++] = Item;
}
T pop (){
Assert (m_nTop> 0 );
Return m_pArray [-- m_nTop];
}
MyStack (const MyStack <T> & otherArray)
{
// Deep copy it
};
Private:
T * m_pArray;
Int m_nTop;
Int m_nCapacity;
};
The MyStack process is as follows:
View plaincopy to clipboardprint? MyStack <CComPtr <ICalculator> g_myStack (1000 );
Void func ()
{
For (int I = 0; I <500; I ++)
{
CComPtr <ICalculator> spCalculator = NULL;
SpCalculator. CoCreateInstance (CLSID_CALCULATOR );
G_myStack.push (spCalculator );
}
...
For (int I = 0; I <500; I ++)
{
CComPtr <ICalculator> spCalculator = g_myStack.pop ();
SpCalculator-> DoSomething ();
}
}
MyStack <CComPtr <ICalculator> g_myStack (1000 );
Void func ()
{
For (int I = 0; I <500; I ++)
{
CComPtr <ICalculator> spCalculator = NULL;
SpCalculator. CoCreateInstance (CLSID_CALCULATOR );
G_myStack.push (spCalculator );
}
...
For (int I = 0; I <500; I ++)
{
CComPtr <ICalculator> spCalculator = g_myStack.pop ();
SpCalculator-> DoSomething ();
}
}
The 500 CoCreateInstance () operation may make you feel crazy. But I just want to let you know how memory leakage happens.
Why? In this case, smart pointers cannot automatically release the corresponding resources. First, they are in the global space. If you want to wait ~ The Destructor MyStack () may need to wait until the program ends. However, after pop, we should not store the smart pointer reference to the interface in MyStack. Imagine that there would never be more than 500 elements in this MyStack. Then, the resources in the second half of MyStack will never be released.
Therefore, when you must manually release the COM component, do not think that the smart pointer will help you complete it. Just rewrite the pop () function and solve the resource leakage problem.
View plaincopy to clipboardprint? Template <typename T>
Class MyStack
{
Public:
....
T pop (){
Assert (m_nTop> 0 );
T tempArray = m_pArray [-- m_nTop];
M_pArray = NULL; // or use m_pArray.Release ();
Return tempArray;
}
Private:
....
};
Template <typename T>
Class MyStack
{
Public:
....
T pop (){
Assert (m_nTop> 0 );
T tempArray = m_pArray [-- m_nTop];
M_pArray = NULL; // or use m_pArray.Release ();
Return tempArray;
}
Private:
....
};
Keep in mind that smart pointers only help us manage memory. You must release COM resources in advance. This section can end.
Author's "liuchang5 column"