为什么不调用重写的“operator new”?
我在 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;
}
我输入一个足够长的字符串(比小字符串优化缓冲区长):
0123456789012345678901234567890123456789012345678901234567890123456789
在调试编译中,进程返回 1,在发布配置中,进程返回 0,这意味着 new
运算符未被调用!我可以通过设置断点、写入输出/调试输出等来验证这一点...
为什么会这样,它是否符合标准行为?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
经过一番研究,@bart-jan 在其他答案(现已删除)中所写的内容实际上是正确的。
可以很容易地看出,Release 中根本没有调用mine Operator,而是调用了CRT 版本。 (不,对于所有在黑暗中拍摄的人来说,这里没有递归。)问题是“为什么”?
上面的代码是针对动态链接的 CRT(这是默认的)进行编译的。 Microsoft 在 CRT DLL 中提供了 std::string 的实例化(以及许多其他标准模板)。查看 VS2005 附带的 Dinkumware 标头:
其中
_CRTIMP2_PURE
扩展为__declspec(dllimport)
。这意味着在 Release 中,链接器将std::string
链接到构建 CRT 时实例化的版本,该版本使用new
的默认实现。目前还不清楚为什么它在调试中不会发生。正如@Violet Giraffe 所猜测的那样,它一定受到某些开关的影响。但是,我认为这是链接器开关,而不是编译器开关。我无法准确确定哪个开关很重要。
其他答案忽略的剩下的问题是“它是标准的”吗?在VS2010中尝试代码,无论我编译什么配置,它确实都会调用我的
operator new
!查看 VS2010 附带的标头,可以发现 Dinkumware 删除了上述实例化的__declspec(dllimport)
。因此,我相信旧的行为确实是编译器错误,并且不是标准。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:Where
_CRTIMP2_PURE
expands to__declspec(dllimport)
. That means that in Release the linker links thestd::string
to the version that was instantiated when the CRT was built, which uses the default implementation ofnew
.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.调用 cout <<来自 new 运算符或其中被调用函数之一的 std::string() 将导致不可预测的程序行为。不要使用新运营商的 io。这样做可能会重新进入您的新操作员。
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.
您确实应该逐步调试代码。您是否尝试在发布配置中设置 /Od 来禁用优化?我想知道这是否会改变行为。
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.
你有无限递归。
相反,喜欢
You have infinite recursion.
Instead, do like