【问题标题】:Overloading global new and delete safely安全地重载全局new和delete
【发布时间】:2011-07-18 00:13:15
【问题描述】:

在阅读 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 指针,但最终我们获得了指向动态分配对象的指针。那么它是一个构造函数返回一个指向对象的指针(this,尽管构造函数没有返回类型)还是它的编译器在内部执行 i?

【问题讨论】:

    标签: c++ dynamic memory-management


    【解决方案1】:

    1) C++ 标准包含许多通常不使用的“可能”。这是其中之一。 operator可以使用动态内存,但不是必须的。通常情况并非如此。

    所以你的例子有效并不意味着它是正确的。这只是意味着它适用于您正在使用的实现。在其他实现上它可能会中断。

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

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

    【讨论】:

      【解决方案2】:
      1. 使用printf() 来避免递归调用operator new() 是一种安全措施——只是为了确保它有效。你怎么知道iostream 的使用永远不会导致对operator new() 函数的调用?

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

      【讨论】:

      • 您是否愿意为 1) 写一个示例,其中 is 可能导致问题 .. 对于 2) 新表达式..首先调用 operator new() 以返回 void*..然后编译器调用c'tor..最后我们得到一个指向已分配+intilized对象的指针..这就是为什么我认为这个指针是由c,tor返回的
      • @user388338:想象一下&lt;&lt; 变成cout 尝试new 某事 - 你有一个递归调用。构造函数没有返回值,所以构造函数不能返回指针。
      • 你的意思是像 cout
      • @user388338:不,我的意思是当您执行cout &lt;&lt; 时,会调用一些C++ 代码,它会调用C++ 库中的某些内容,而库中的代码可以new 用于其自身目的。
      • 关于第 1 点:标准允许 printf 和 ostream 都使用 operator new。随着安全措施的进行,这只是一种可能的解决方案,而不是有保证的解决方案。 (在我自己的代码中,我检查递归,如果我在递归调用中,则不打印。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-07
      相关资源
      最近更新 更多