为什么覆盖操作符new不是调用?

时间:2011-11-24 12:40:53

标签: c++ visual-studio-2005 operator-overloading new-operator

我在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

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

为什么会这样,它是一种标准的符合行为?

4 个答案:

答案 0 :(得分:5)

经过一些研究,@ bart-jan在他的第二个答案中写道(虽然没有人将其删除,但现在已被删除)实际上是正确的。

由于可以很容易地看到我的操作符根本没有在Release中调用,而是调用了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)以进行上述实例化。因此,我认为旧的行为确实是一个编译器错误,不是标准。

答案 1 :(得分:0)

调用cout&lt;&lt;来自您的新运算符或其中一个被调用函数的std :: string()将导致不可预测的程序行为。不要使用新操作员的io。做这样的事情可能会重新进入你的新运营商。

答案 2 :(得分:0)

你真的应该逐步调试代码。您是否尝试在发布配置中设置/ Od以禁用优化?我想知道这是否会改变行为。

答案 3 :(得分:-1)

你有无限的递归。

相反,喜欢

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