重载全局new并安全删除

时间:2011-03-18 08:46:00

标签: c++ dynamic memory-management

在阅读Bruce Eckel时,我遇到了以下示例:

#include <cstdio>
#include <cstdlib>
using namespace std;
void* operator new(size_t sz) 
{
  printf("operator new: %d Bytes\n", sz);
  void* m = malloc(sz);
  if(!m) puts("out of memory");
   return m;
}

void operator delete(void* m) 
{
 puts("operator delete");
 free(m);
}
 class S {
 int i[100];
 public:
 S() { puts("S::S()"); }
 ~S() { puts("S::~S()"); }
 };

int main() {
puts("creating & destroying an int");
int* p = new int(47);
delete p;
puts("creating & destroying an s");
S* s = new S;
delete s;
puts("creating & destroying S[3]");
S* sa = new S[3];
delete []sa;
} 

我怀疑以下陈述:

  1. 请注意,我使用printf( )puts( )而不是iostream。这是因为在创建iostream对象时(如全局cincoutcerr),它会调用operator new来分配内存。使用printf( ),您不会陷入僵局,因为它没有调用new来初始化自己。
    但是,当我在用cout替换put之后运行程序时,我没有遇到这样的死锁。任何人都可以解释一下吗?

  2. operator new返回一个void指针,但最后我们得到了一个动态分配对象的指针。那么它是一个构造函数,它返回一个指向该对象的指针(虽然构造函数没有返回类型)或者它内部的编译器吗?

2 个答案:

答案 0 :(得分:2)

1)C ++标准包含许多通常不使用的“mays”。这是其中之一。运算符&lt;&lt;函数可能使用动态内存,但它没有。通常情况并非如此。

因此,您的示例有效并不意味着它是正确的。它只是意味着它适用于您正在使用的实现。在其他实现中它可能会破坏。

标准定义的“mays”也可以向另一个方向发展。例如,任何STL-Header可以包括任何其他标准头,但不是必须这样做。这通常是iostream标头以及istream和ostream标头的情况。当使用iostream时,几乎任何实现都包括ostream和istream,但从技术上讲它们并不需要。这意味着当你使用ostream并且只包含iostream时,程序可能会起作用,但实际上就标准而言它是不正确的。

对于c和c ++来说,知道什么可能会默默地破坏是非常重要的,但这通常不是很容易。

答案 1 :(得分:1)

  1. 使用printf()来避免递归调用operator new()是一种安全措施 - 只是为了确保它有效。你怎么知道使用iostream永远不会调用operator new()函数?

  2. 您使用operator new()函数混淆了新表达式(一种语言结构)。 新表达式确实会返回一个类型化指针,但是对operator new()函数的调用是在“引擎盖下”完成的,operator new()函数返回void*。编译器为此生成所有必要的代码。