【问题标题】:Are there any problems with this overload of operator new?这个 operator new 的重载有什么问题吗?
【发布时间】:2011-03-25 01:43:53
【问题描述】:

我正在考虑我可能会写一些内存池/分配的东西,所以我想出了这个operator new 重载,我想用它来促进内存的重用。我想知道你们在我的实现(或任何其他可能的问题)中是否有任何问题。

#include <cstddef>

namespace ns {
    struct renew_t { };
    renew_t const renew;
}

template<typename T>
inline void * operator new(std::size_t size, T * p, ns::renew_t renew_constant) {
    p->~T();
    return p;
}

template<typename T>
inline void operator delete(void *, T *, ns::renew_t renew_constant) { }

可以这样使用

int main() {
    foo * p(new foo());        // allocates memory and calls foo's default constructor
    new(p, ns::renew) foo(42); // calls foo's destructor, then calls another of foo's constructors on the same memory
    delete p;                  // calls foo's destructor and deallocates the memory
}

【问题讨论】:

  • 赋值运算符是重用内存的好方法。
  • 这不是一个好主意。内存管理系统非常有效(加上调整和正确)。除非您已经拥有大量运行时内存管理经验,否则自己编写是自找麻烦。

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


【解决方案1】:

delete() 运算符没有调用对象的析构函数,这出乎我的意料。

我不得不对new(p, ns::renew) foo(42) 进行双重处理。对我来说,这根本不直观。

您可能真正想要的是将分配内存的过程和构造对象的过程分开。对于这种情况,您通常使用"placement new"

// Not exception safe!

void* p = ::operator new(sizeof(T)); // allocate raw memory

new(p) T(41); // construct a T at this memory location
p->~T();      // destruct T

new(p) T(42); // recreate a different T at the same memory location
p->~T();      // destruct T

::operator delete(p); // deallocate raw memory

在真正的内存池应用程序中,你会wrap the above lines into a MemoryPool class of some sort.

当然,这仅适用于您实际直接处理内存以实现实际内存池或容器分配器的目的。在其他情况下,you're better off overloading the = operator() as suggested by Potatoswatter

【讨论】:

  • operator delete 重载什么都不做,因为它是一个展示位置删除。标准 C++ 库中的放置删除也不做任何事情。它本质上是无用的,但由于某种原因需要定义。该语法是必需的,因为它是放置新语法。通常placement new 是这样调用的,但没有renew 常量参数。
  • 哦,我忘了结束我关于语法的观点;我的目标是模仿 C++ 标准库提供的 operator newno_throw 重载的语法。 void * operator new (std::size_t size, const std::nothrow_t &amp; nothrow_constant) throw();
  • @Silver:在使用自定义 new 后构造抛出时使用“放置删除”。这正是您无法处理的情况。
【解决方案2】:

请阅读http://www.gotw.ca/gotw/022.htmhttp://www.gotw.ca/gotw/023.htm

真的,您应该定义operator=,而不是使用析构函数玩游戏。在混合中添加operator new(和operator delete,YUCK!)过载只会增加痛苦。

而且,正如 C++ 大神 Herb Sutter 在这些链接中所建议的那样,您可以简单地根据 operator= 定义构造函数。

【讨论】:

    【解决方案3】:

    应该是好的,只要你不尝试一些疯狂的事情并尝试更新一个子类。既然你说这是游泳池,那应该没问题。

    也就是说,我唯一的问题是 - 什么更清晰?这是一个品味问题,但想象一下其他人可能需要查看代码。您基本上只是将两个简单明了的语句压缩成一个需要更深入地了解代码内部功能的语句。

    在我的池函数中,我通常有两种单独的方法,一种用于销毁,一种用于构造,它们基本上都在做你在这里所做的事情(p->~T 和 new(p) T()),但至少你知道他们做了什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      相关资源
      最近更新 更多