为什么覆盖的运营商新的不是呼叫? [英] Why the overrided operator new isn't call?

查看:150
本文介绍了为什么覆盖的运营商新的不是呼叫?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在VS2005上运行以下代码:

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


b $ b

在Debug编译中,进程返回1,在Release配置中,进程返回0,这意味着不会调用新的运算符!我可以通过放置断点,写入输出/调试输出等来验证这一点。

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 his second answer (which is now deleted although no-one downvoted it) is in fact correct.

由于很容易看出,发布版本中没有调用操作符,而是调用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提供了一个实例化std :: string(在许多其他标准模板)之间的CRT DLL。查看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时实例化的版本,它使用默认实现

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.

这里大家都忽略的另一个问题是是标准的吗?尝试VS2010中的代码,它确实调用我的运算符新无论什么配置我编译!查看VS2010附带的标题显示,Dinkumware 已删除 __ declspec(dllimport),用于上述实例化。因此,我相信旧的行为确实是一个编译器错误,而不是标准。

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.

这篇关于为什么覆盖的运营商新的不是呼叫?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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