Why the overrided operator new isn't call?

独自空忆成欢 提交于 2019-12-23 20:22:42

问题


I run the following code on 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?


回答1:


After some research, what @bart-jan wrote in his second answer (which is now deleted although no-one downvoted it) 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 find what exactly switch matters.

The other left question which everyone here ignored is "is it standard"? Trying the code in VS2010, it indeed called my operator new no matter what configuration I compile! Looking in the headers shipped with VS2010 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.




回答2:


Calling cout << std::string() from your new operator or one of the called functions within, will cause unpredicable program behavour. Don't use io from your new operator. Doing things like that may re-enter your new operator.




回答3:


You really should debug the code step-by-step. Did you try setting /Od in your release configuration to disable optimization? I wonder if that changes the behaviour.




回答4:


You have infinite recursion.

Instead, do like

#include <iostream>
#include <string>
#include <new>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

void* my_alloc( char const* str, std::size_t size )
{
    fprintf( stderr, "%s %lu\n", str, (unsigned long)size );
    return malloc( size ); // I don't care for errors here
}

void* operator new( std::size_t size )      { return my_alloc( "new", size ); }
void operator delete( void* ptr )           { free(ptr); }
void* operator new[]( std::size_t size )    { return my_alloc( "new[]", size ); }
void operator delete[]( void* ptr )         { free( ptr ); }

int main()
{
    std::string str;
    std::cout << "? ";
    std::getline(std::cin, str);
    std::cout << str;
}


来源:https://stackoverflow.com/questions/8257236/why-the-overrided-operator-new-isnt-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!