why is a scalar deleting destructor being called as a result of vector delete on Windows?
I have a code that is leaking on Windows. It runs fine on many unix platforms and the leak only occurs on Windows. The binary consists of exe, 1 dll and 2 static libs. The exe links to both the dll and the static libs, while the static libs link with the dll as well. The leak occurs in the exe code when instead of calling to a vector deleting destructor, for some reason scalar deleting destructor is called. This results in only the first object in the array to be deleted while the rest of the array stays in memory.
The leaking pseudo-code looks like this:
class MyClassFromExe : public MyBaseClassFromDll {
public:
ClassFromDll* m_arr;
MyClassFromExe(unsigned int size)
{
m_arr = new ClassFromDll[size];
}
~MyClassFromExe()
{
delete [] m_arr;
}
};
void func()
{
MyClassFromExe obj(3);
}
When func() finishes and the destructor is called I see that only the destructor of the first object in m_arr is called. From debugger I see that this is done from scalar deleting destructor and not from vector deleting destructor. This explains why only the first object is destroyed. What I need to understand is why scalar deleting destructor is called when delete [] is used???
I found this thread - Why is vector deleting destructor being called as a result of a scalar delete?. I followed the suggestions there and made sure that all the modules are compiled with /MD.
Important to notice that when the dll that contains ClassFromDll was a static library and not a dll, everythin开发者_开发问答g worked fine. The leak started only when the static library was changed to be a dll. While the program leaks in Release mode, it crashes in Debug mode on delete [] m_arr. The crash occurs in dbgdel.cpp line 52 - _BLOCK_TYPE_IS_VALID(pHead->nBlockUse).
On unix platforms this lib is also a shared lib and as expected vector deleting destructor is called there and there is no leak. Could the problem be with the VC compiler? Or maybe some other settings of the projects need to be changed? I'm using VC2003.
Thank you in advance!
This is an old Problem in VC++ regarding DLLs and Object-Arrays. The cause is an incorrect compiler optimization as explained by Microsoft.
http://support.microsoft.com/kb/121216/en-us
Better use the STL-containers which dont have the problem due to the use of allocator.
A class in a DLL is extremely touchy, without much help from compilers. Check out this answer for details WHY this is problematic: How can I call a function of a C++ DLL that accepts a parameter of type stringstream from C#?.
Short version: if the class interface uses ANY inlined code, you will experience potential problems exactly like this. Any templated object (such as std::string
) included.
I would guess this is why. It is similar to the problem @Mikael Persson suggests.
I think this is a clear case of allocating on one heap and deleting on another (remember that the delete[] has to query the heap for the number of elements in the array, and if the heap does not even contain this pointer, it will return "error" (not really) and it will be assumed that it is just one element and use the scalar delete instead). I think that the problem you have was lost in trying to boil it down to a simple example code. I would suggest you read this article (it's old, but the deletion technique is still very relevant, I use a variation of that technique myself and it works like a charm). One modern way to do this is to attach a deletion function pointer to a smart pointer (shared_ptr) that handles your object, this way, by assigning this deletion function pointer at the same time as you create the object in a factory function, you ensure that the delete will be called on the same heap that it was allocated from.
In general I'd recommend using a std::vector<ClassFromDLL> instead of ClassFromDLL*. Construct it passing in size. Deletion will then be automatic. Unfortunately I don't have much experience with delete[], because I always let the standard library do that for me ;-)
Peeking at the code, I'd assume the object was copied by the default copy ctor, which leads to a double-deletion bug. This is Undefined Behavior. It may appear to work, but break due to seemingly unrelated changes - such as switching from a LIB to a DLL.
精彩评论