Operator new applies to std::vector but not std::string?
I'm running into a very odd issue with Visual Studio 2005+SP1. In
short, I've added a global operator new, and it's picked up by
std::vector, and possibly other stl containers. However, it is NOT
picked up by std::string. I've cut down source code to what I believe
is a pretty minimal test case -- copy the following source into a
file, e.g. 'main.cpp', and make a win32 console app that uses it. The
source code is towards the bottom of this post.
The output is as follows:
Pre vector test
In CheapPoolAlloc
In CheapPoolAlloc
In CheapPoolFree
In CheapPoolAlloc
In CheapPoolFree
In CheapPoolAlloc
In CheapPoolFree
In CheapPoolFree
Post vector test
Pre string test
Post string test
This shows that the std::vector used in my code is using my custom
global operator new/delete. However, std::string is ignoring my
request. Doing a little go-to-disassembly fun with a release build,
I've found that _malloc is at 0x78134d09. [Note: probably will NOT
work outside of 2005+SP1]. If I put a breakpoint there, I see that
it gets hit with the following callstack:
msvcr80.dll!_malloc()
msvcr80.dll!operator new() + 0x1d bytes
msvcp80.dll!std::_Allocate<char>() + 0x15 bytes
msvcp80.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy() + 0x55 bytes
msvcp80.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow() + 0x22 bytes
msvcp80.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign() + 0x3e bytes
msvcp80.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign() + 0x19 bytes
OperatorNewTest.exe!main() Line 77 C++
Where line 77 is the line after the line that says str = "This is a
long string to[...]";. So, it seems as if the std::_Allocate<char>
calls a different operator new() than the one I've overridden. Is this
a bug in my code, or some limitation of std::string? Thanks for any
help.
---- Begin file: main.cpp
#include <windows.h>
// Cheap memory pool. Do NOT use this in production code.
static char gPool[65536];
static size_t gPoolOffset;
void* CheapPoolAlloc(size_t s)
{
char* nextFree = gPool + gPoolOffset;
gPoolOffset += s;
OutputDebugString("In CheapPoolAlloc\n");
return reinterpret_cast<void*>(nextFree);
}
void CheapPoolFree(void* p)
{
OutputDebugString("In CheapPoolFree\n");
}
inline void* operator new(size_t reportedSize)
{
return CheapPoolAlloc(reportedSize);
}
inline void* operator new[](size_t reportedSize)
{
return CheapPoolAlloc(reportedSize);
}
inline void* operator new(size_t reportedSize, const char* /*pSourceFile*/, int /*sourceLine*/)
{
return CheapPoolAlloc(reportedSize);
}
inline void* operator new[](size_t reportedSize, const char* /*pSourceFile*/, int /*sourceLine*/)
{
return CheapPoolAlloc(reportedSize);
}
inline void operator delete(void* pReportedAddress)
{
CheapPoolFree(pReportedAddress);
}
inline void operator delete[](void* pReportedAddress)
{
CheapPoolFree(pReportedAddress);
}
#include <stdio.h>
#include <stdlib.h>
// Operator new defined before including vector/string.
#include <vector>
#include <string>
int main()
{
OutputDebugString("Pre vector test\n");
{
// These memory allocations should cause CheapPoolAlloc/Free
// to say something, and do.
std::vector<int> vec;
vec.push_back(0);
vec.push_back(0);
vec.push_back(0);
vec.push_back(0);
// Going out of scope should kill vec, release memory.
}
OutputDebugString("Post vector test\n");
OutputDebugString("Pre string test\n");
{
// These memory allocations should cause CheapPoolAlloc/Free
// to say something, but don't.
std::string str;
str = "This is a long string to test out memory allocations.";
// Going out of scope should kill str, release memory.
}
OutputDebugString("Post string test\n");
return 0;
}
---- end file main.cpp
--
<*> Nathan Mates - personal webpage http://www.visi.com/~nathan/
# Programmer at Pandemic Studios -- http://www.pandemicstudios.com/
# NOT speaking for Pandemic Studios. "Care not what the neighbors
# think. What are the facts, and to how many decimal places?" -R.A. Heinlein