为什么不调用重写的“operator new”?

发布于 2024-12-17 14:38:33 字数 832 浏览 1 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧情别恋 2024-12-24 14:38:33

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

可以很容易地看出,Release 中根本没有调用mine Operator,而是调用了CRT 版本。 (不,对于所有在黑暗中拍摄的人来说,这里没有递归。)问题是“为什么”?

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

#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 的默认实现。

目前还不清楚为什么它在调试中不会发生。正如@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:

#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 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.

枫以 2024-12-24 14:38:33

调用 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.

小ぇ时光︴ 2024-12-24 14:38:33

您确实应该逐步调试代码。您是否尝试在发布配置中设置 /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.

喜爱纠缠 2024-12-24 14:38:33

你有无限递归。

相反,喜欢

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

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文