【问题标题】:What are the limitations of overloading, overriding and replacing new/delete?重载、覆盖和替换新/删除的限制是什么?
【发布时间】:2012-02-03 23:15:09
【问题描述】:

我了解有3 general ways可以修改C++中new和delete的行为:

  • 替换默认的new/delete和new[]/delete[]
  • 覆盖重载放置版本(覆盖传递给它的内存位置的版本,在创建传递其他类型或数量的参数的版本时重载)
  • 重载类特定版本。

对new/delete的行为进行这些修改有什么限制?

特别是对 new 和 delete 可以使用的签名有限制吗?

如果任何替换版本必须具有相同的签名是有意义的(否则它们不会被替换或会破坏其他代码,例如 STL),但是是否允许全局放置或特定类的版本返回智能例如指针或一些自定义句柄?

【问题讨论】:

标签: c++ operator-overloading new-operator delete-operator


【解决方案1】:

当您在一个类中重载 new 和 delete 时,您实际上是在修改为该类分配和释放内存的方式,要求它为您提供这种控制权。

当一个类想要使用某种池来分配它的实例时,可以这样做,无论是为了优化还是为了跟踪。

限制,与几乎所有运算符重载一样,是您可以传递的参数列表,以及它应该遵守的行为。

【讨论】:

  • 是的,“限制......[是]您可以传递的参数列表,以及它应该遵守的行为。”标准行为在针对该问题发布的链接中进行了概述,但是我必须传递哪些参数列表?如果它和其他运营商非常相似,我可以做任何事情。它可以是什么返回类型?
【解决方案2】:

首先,不要将 new/delete 表达式operator new() 函数混淆。

表达式是一种执行构造和破坏的语言结构。运算符是一个执行内存(解除)分配的普通函数。

只有默认的运算符(operator new(size_t)operator delete(void *) 可以与默认的 newdelete 表达式一起使用。所有其他表单统称为“放置”表单,对于那些您只能使用 @987654326 @, 但是你必须通过调用析构函数来手动销毁对象。放置形式是相当有限和专门的需求。到目前为止,最有用的放置形式是全局放置新,::new (addr) T,但它的行为甚至无法改变(这大概就是为什么它是唯一受欢迎的)。

所有new 运算符必须返回void *。这些分配函数远比你想象的要低级得多,所以基本上你“会知道什么时候需要处理它们”。

重复一遍:C++ 将对象构造和内存分配的概念分开。您所能做的就是为后者提供替代实现。

【讨论】:

  • 好理解,分配和构造是分开的任务。所以经常使用new关键字执行分配和构造,而放置新形式只执行构造?所以我猜所有的放置形式都需要有一个 void * 才能知道在哪里构造对象?还是让编译器知道在哪里构造对象?如果 new 的放置版本被告知在哪里构造,它们是否还需要返回一个 void *?
  • 只有全局默认的placement-new (::operator new(size_t, void *)) 保证是空操作。其他放置形式,以及类成员函数,可以为所欲为。 new-operator 的每一种形式都必须返回一个void *,它成为对象的this 指针。
  • 对,我想我现在做得更好了。所以只有默认的全局位置 new 保证不分配,但任何自定义的..它们是自定义的,可能分配也可能不分配。但是它们都返回 void * 并且编译器接受这个 void *,使它成为 *this 并调用构造函数在那个内存位置构造对象。这是正确的吗?我得出的结论是,没有重载的 new 运算符显式调用构造函数,这一切都是在 operator new 执行“分配”之后由编译器完成的。
  • @Bingo:没错。从某种意义上说,global-default-placement-new 是唯一您可以可靠地手动“调用”构造函数而不做其他任何事情的方式。
猜你喜欢
  • 2011-04-14
  • 2011-03-01
  • 2012-09-04
  • 2011-11-11
  • 2012-12-23
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多