Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global overload delete[] not called in third-party libraries

I'm trying to learn about memory pools in C++ for better speed and debugging capabilities. I've been following the approach found here: http://oroboro.com/overloading-operator-new/. So I've overloaded new, new[], delete, and delete[] like this:

inline void* operator new     ( size_t size ) { return myAlloc( size ); }
inline void* operator new[]   ( size_t size ) { return myAlloc( size ); }
inline void  operator delete  ( void* ptr   ) { myFree( ptr ); }
inline void  operator delete[]( void* ptr   ) { myFree( ptr ); }

I like that third-party libraries are directed to this version of new, but I ran into a problem. I am making a DirectX application that uses DXUT. I compile DXUT separately from my project. Eventually it calls:

std::unique_ptr<D3D11_SUBRESOURCE_DATA[]> initData( new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] );

Once this unique pointer goes out of scope, it crashes on a call to delete[] _Ptr, which did not go through my overloaded operator. I tried debugging my memory pool implementation by adding a int* dummy = new int[10]; delete[] dummy; in my main. Building the project gave an error, but clean-building worked fine. To my surprise, everything worked, including the DXUT line that was crashing!

Question 1: What exactly happened when I added the debugging line that fixed the issue? I guess for some reason my operator delete[] was not known until I called it in my own application code? Is this guaranteed to fix the problem or is it just dumb luck?

Question 2: I noticed that the new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] did not call my operator new[] directly, but eventually called my operator new (no brackets). It still calls operator delete[] on the pointer. Does this pose an issue? Do I have to add the appropriate overload such that my operator new[] is called or is this behavior fine?

For reference, the operator new[] overload that was called was:

void * __CRTDECL operator new[](::size_t count, const std::nothrow_t& x)
_THROW0()
{ // Try to allocate count bytes for an array
    return (operator new(count, x));
}
like image 794
DSM Avatar asked Aug 31 '14 21:08

DSM


People also ask

Why overload new and delete?

The most common reason to overload new and delete are simply to check for memory leaks, and memory usage stats. Note that "memory leak" is usually generalized to memory errors. You can check for things such as double deletes and buffer overruns.

Can we overload delete operator in C++?

Overloading New and Delete operator in c++ The new and delete operators can also be overloaded like other operators in C++. New and Delete operators can be overloaded globally or they can be overloaded for specific classes.

How does operator delete work?

operator delete, operator delete[] Deallocates storage previously allocated by a matching operator new. These deallocation functions are called by delete-expressions and by new-expressions to deallocate memory after destructing (or failing to construct) objects with dynamic storage duration.


1 Answers

Question 1: What exactly happened when I added the debugging line that fixed the issue? I guess for some reason my operator delete[] was not known until I called it in my own application code? Is this guaranteed to fix the problem or is it just dumb luck?

§3.2 [basic.def.odr]/p4:

An inline function shall be defined in every translation unit in which it is odr-used.

It sounds like that your compiler didn't generate code for global operator delete[] since it's not used in your main translation unit and is marked inline (meaning that the compiler can assume that any translation unit that uses them will have a definition of them). However, your separately compiled library doesn't have a definition of those functions, and you end up using the default ones from the standard library. Making them non-inline should fix the problem.

Question 2: I noticed that the new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] did not call my operator new[] directly, but eventually called my operator new (no brackets). It still calls operator delete[] on the pointer. Does this pose an issue? Do I have to add the appropriate overload such that my operator new[] is called or is this behavior fine?

The default versions of both throwing and nonthrowing versions of operator new [], as well as the nonthrowing version of operator new, are specified to call the throwing version of operator new to obtain memory. So you are safe there. However, your operator new's definitions are likely wrong. They must return a valid pointer or throw an exception. Returning a null pointer is not allowed.

like image 72
T.C. Avatar answered Oct 12 '22 22:10

T.C.