C ++:关于重载operator new的一般想法

时间:2011-03-11 22:17:29

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

您是否在C ++中重载了operator new

如果是,为什么?

面试问题,我谦卑地请求你的一些想法。

6 个答案:

答案 0 :(得分:7)

我们有一个嵌入式系统,其中很少允许new,并且永远不会删除内存,因为出于可靠性原因我们必须证明最大堆使用率。

我们有一个不喜欢这些规则的第三方图书馆开发人员,所以他们重载newdelete来对抗我们为他们分配的一大块内存。

答案 1 :(得分:4)

重载operator new让您有机会控制对象在内存中的位置。我之所以这样做是因为我知道有关对象生命周期的一些细节,并希望避免在没有虚拟内存的平台上出现碎片。

答案 2 :(得分:2)

如果你使用自己的分配器,做一些花哨的引用计数,检测垃圾收集,调试对象生命周期或完全不同的东西,你会超载new;你正在替换对象的分配器。我个人不得不这样做,以确保在特定的mmap内存页面上分配某些对象。

答案 3 :(得分:2)

是的,原因有两个:自定义分配器和自定义分配跟踪。

答案 4 :(得分:1)

如果由于某种原因想要进行自定义分配(即避免c-runtime分配器固有的内存碎片或/和避免多线程程序中的内存管理调用锁定),乍一看重载新运算符可能看起来不错。但是当你开始实现时,你可能会意识到在大多数情况下你想要为这个调用传递一些额外的上下文,例如给定大小的对象的特定于线程的堆。并且重载new / delete根本不起作用。因此,最终您可能希望为自定义内存管理子系统创建自己的外观。

答案 5 :(得分:0)

我发现在C ++中编写Python扩展代码时重载operator new非常方便。我分别在operator newoperator delete重载中包装了用于分配和释放的Python C-API代码 - 这允许PyObject* - 兼容的结构,可以使用new MyType()创建使用可预测的堆分配语义进行管理。

它还允许将分配代码(通常在Python __new__方法中)和初始化代码(在Python的__init__中)分别分离为operator new重载和任何人认为适合定义的构造函数。

以下是一个示例:

struct ModelObject {

    static PyTypeObject* type_ptr() { return &ModelObject_Type; }

    /// operator new performs the role of tp_alloc / __new__
    /// Not using the 'new size' value here
    void* operator new(std::size_t) {
        PyTypeObject* type = type_ptr();
        ModelObject* self = reinterpret_cast<ModelObject*>(
            type->tp_alloc(type, 0));
        if (self != NULL) {
            self->weakrefs = NULL;
            self->internal = std::make_unique<buffer_t>(nullptr);
        }
        return reinterpret_cast<void*>(self);
    }

    /// operator delete acts as our tp_dealloc
    void operator delete(void* voidself) {
        ModelObject* self = reinterpret_cast<ModelObject*>(voidself);
        PyObject* pyself = reinterpret_cast<PyObject*>(voidself);
        if (self->weakrefs != NULL) { PyObject_ClearWeakRefs(pyself); }
        self->cleanup();
        type_ptr()->tp_free(pyself);
    }

    /// Data members
    PyObject_HEAD
    PyObject* weakrefs = nullptr;
    bool clean = false;
    std::unique_ptr<buffer_t> internal;

    /// Constructors fill in data members, analagous to __init__
    ModelObject()
        :internal(std::make_unique<buffer_t>())
        ,accessor{}
        {}

    explicit ModelObject(buffer_t* buffer)
        :clean(true)
        ,internal(std::make_unique<buffer_t>(buffer))
        {}

    ModelObject(ModelObject const& other)
        :internal(im::buffer::heapcopy(other.internal.get()))
        {}

    /// No virtual methods are defined to keep the struct as a POD
    /// ... instead of using destructors I defined a 'cleanup()' method:
    void cleanup(bool force = false) {
        if (clean && !force) {
            internal.release();
        } else {
            internal.reset(nullptr);
            clean = !force;
        }
    }

    /* … */

};