为什么不调用覆盖的“operator new"? [英] Why the overriden `operator new` isn't called?

查看:57
本文介绍了为什么不调用覆盖的“operator new"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 VS2005 中运行以下代码:

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

在 Debug 编译过程中返回 1,在 Release 配置中过程返回 0,这意味着 new 操作符没有被调用!我可以通过放置断点、写入输出/调试输出等来验证这一点...

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?

推荐答案

经过一番研究,@bart-jan 在他们的另一个答案(现已删除)中所写的内容实际上是正确的.

After some research, what @bart-jan wrote in their other answer (now deleted) is in fact correct.

很容易看出,在 Release 中根本没有调用 mine 操作符,而是调用了 CRT 版本.(不,对于所有在黑暗中拍摄的人来说,这里没有递归.)问题是为什么"?

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"?

以上是针对动态链接的 CRT(这是默认设置)编译的.Microsoft 在 CRT DLL 中提供了 std::string(以及许多其他标准模板)的实例化.查看 VS2005 随附的 Dinkumware 标头:

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> >;

其中 _CRTIMP2_PURE 扩展为 __declspec(dllimport).这意味着在 Release 中,链接器将 std::string 链接到构建 CRT 时实例化的版本,该版本使用 new 的默认实现.

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.

不清楚为什么它不会在调试中发生.正如@Violet Giraffe 猜对的那样,它必须受到某些开关的影响.但是,我认为是链接器开关,而不是编译器开关.我无法确切确定哪个开关重要.

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.

其他答案忽略的剩余问题是它是标准的吗"?在VS2010中尝试代码,无论我编译什么配置,它确实都调用了我的operator new!查看 VS2010 附带的标头,它显示 Dinkumware 删除上述实例化的 __declspec(dllimport).因此,我认为旧行为确实是编译器错误,并且不是标准.

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.

这篇关于为什么不调用覆盖的“operator new"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆