编程C++ 开发者,系统程序员

请介绍一下 C++ 中的 operator new/operator delete 机制。它们与 new/delete 有什么不同?何时以及为什么要在用户自定义类中重载运算符函数?

用 Hintsage AI 助手通过面试

答案。

在 C++ 中,operator newoperator delete 是在通过 newdelete 操作符分配和释放内存时调用的内存分配和释放函数。默认情况下,它们使用标准分配器,但可以在类中重载,以便更细致地控制内存分配。

  • operator new 分配 "原始" 内存块,而不调用构造函数。
  • 在内存分配之后,自动调用对象的构造函数。
  • operator delete 在对象的析构函数完成后释放内存。

用法(全局和局部版本):

  • 默认使用全局版本(例如,使用 new int 时)。
  • 通过在类中重载特定的 operator new,可以优化该类对象的内存使用(例如,对象池、跟踪、重用内存块)。

operator new/operator delete 重载示例:

#include <iostream> class TrackAlloc { public: void* operator new(size_t size) { std::cout << "TrackAlloc::new for " << size << " bytes "; return ::operator new(size); } void operator delete(void* ptr) { std::cout << "TrackAlloc::delete "; ::operator delete(ptr); } };

细节:

  • 带参数的新建/删除对象(定位 new)需要单独重载。
  • 重载的运算符仅在创建/删除类对象时被调用,而不适用于 new[]/delete[]。可以为它们单独重载 operator new[]/delete[]。
  • 内存操作是危险的 — 需要正确处理异常。

有陷阱的问题。

"如果在类中重载了 operator new,然后通过变量创建继承类的对象,会发生什么?将调用哪个版本的 operator new?"

答案: 将调用创建对象的类的 operator new。如果派生类未实现 operator new,将尝试在基类中或全局版本中查找合适的版本。

示例:

struct Base { void* operator new(size_t s) { std::cout << "Base new "; return ::operator new(s); } }; struct Derived : Base {}; Derived* p = new Derived; // 将调用 Base::operator new!

因为不知道细节而导致的实际错误示例。


故事

开发人员在没有支持正确异常处理的情况下重载了 operator new / delete。在构造函数内抛出异常时,内存没有被释放,导致内存泄漏。


故事

错误实现了 operator new[] 和 operator delete[]:对于包含数组的类,新实现未被调用 — 使用了默认版本,导致内存分配和释放逻辑不同步。


故事

重载全局 operator new 影响了第三方库的工作:所有对象(包括临时对象和来自 STL 的对象)都开始通过记录分配器进行分配,这严重降低了应用程序内核的性能。