I run the following code in VS2005:
#include <iostream>
#include <string>
#include <new>
#include <stdlib.h>
int flag = 0;
void* my_alloc(std::size_t size)
{
flag = 1;
return malloc(size);
}
void* operator new(std::size_t size) { return my_alloc(size); }
void operator delete(void* ptr) { free(ptr); }
void* operator new[](std::size_t size) { return my_alloc(size); }
void operator delete[](void* ptr) { free(ptr); }
int main()
{
std::string str;
std::getline(std::cin, str);
std::cout << str;
return flag;
}
I enter a long enough string (longer than the small-string-optimization buffer):
0123456789012345678901234567890123456789012345678901234567890123456789
In a Debug compilation the process returns 1, in Release configuration the process returns 0, which means that the new
operator isn't called! I can verify this by putting a breakpoint, writing to output/debug output, etc...
Why is this, and is it a standard conforming behavior?
After some research, what @bart-jan wrote in their other answer (now deleted) is in fact correct.
As it can be easily seen mine operator isn't called in Release at all, instead the CRT version is called. (And no, for all those who shot in the dark, there's no recursion here.) The question is "why"?
The above was compiled against the dynamically linked CRT (which is the default). Microsoft provides an instantiation of std::string
(among many other standard templates) within the CRT DLL. Looking into Dinkumware's headers shipped with VS2005:
#if defined(_DLL_CPPLIB) && !defined(_M_CEE_PURE)
template class _CRTIMP2_PURE allocator<char>;
// ...
template class _CRTIMP2_PURE basic_string<char, char_traits<char>,
allocator<char> >;
Where _CRTIMP2_PURE
expands to __declspec(dllimport)
. That means that in Release the linker links the std::string
to the version that was instantiated when the CRT was built, which uses the default implementation of new
.
It's unclear why it doesn't happen in debug. As @Violet Giraffe guessed correctly it must be affected by some switches. However, I think it's the linker switches, not the compiler switches. I can't determine exactly which switch matters.
The remaining question which other answers ignored is "is it standard"? Trying the code in VS2010, it indeed called my operator new
no matter what configuration I compile! Looking at the headers shipped with VS2010 it reveals that Dinkumware removed the __declspec(dllimport)
for the above instantiation. Thus, I believe the old behavior is indeed a compiler bug, and not standard.