11

我一直在研究自定义分配器,我经常看到它们使用某种函数来分配内存。出于测试目的和进一步教育我自己,我试图做一个“简单”的例子。但是,我了解如何做一件基本的事情。mallocvs的主要区别之一new是使用 new 调用构造函数。如果我想编写自己的分配器,它本质上是替换new,我将如何让构造函数在使用时被调用malloc

我知道在类上我可以重载newdelete类,所以我想问题的很大一部分是,new在分配期间如何调用对象构造函数?同样,我对如何delete调用析构函数感兴趣。

我创建了一个示例测试代码,希望SomeClass在分配期间调用构造函数,但我不知道如何。

#include <malloc.h>

void* SomeAllocationFunction(size_t size) {
    return malloc(size);
}

class SomeClass
{
public:
    SomeClass() {
        int con = 1000;
    }

    ~SomeClass() {
        int des = 80;
    }
};

int main(void){
    SomeClass* t = (SomeClass*)SomeAllocationFunction(sizeof(SomeClass));
    return 0;
}

(作为说明,我知道我可以只使用new。但是,出于学习的目的,我正在尝试创建一个不只是调用的自定义分配器newor placement new)。

4

3 回答 3

16

本质上,当您使用类似的新表达式时T *t = new T;,它大致相当于:

void *temp = operator new(sizeof(T));
T *t = new(temp) T;

因此,首先它使用分配函数分配一些原始内存,然后在该内存中构造一个对象。同样,当您使用像这样的删除表达式时delete t;,它大致相当于:

t->~T();
operator delete(t);

因此,如果您重载new并且delete对于特定类:

class T { 
    int data; 
public:
    // I've made these static explicitly, but they'll be static even if you don't.
    static void *operator new(size_t size) { 
        return malloc(size);
    }
    static void operator delete(void *block) { 
        free(block);
    }
};

然后当你使用一个新的表达式时,它会调用类'operator new来分配内存,这将调用malloc,因此T *t = new T();最终将通过分配内存malloc(同样,当你delete使用它时,它会使用operator delete,这将调用free)。

至少正如通常使用的术语一样,分配器非常相似,只是它由容器而不是其他代码使用。它还将分配函数和删除函数封装在一个类中,所以当你向容器传递一个时,你只需要传递一个对象,分配和删除函数不匹配的可能性很小。

暂时忽略关于事物使用名称的细节,标准库中的 Allocator 类大部分都做同样的事情,所以稍微重命名T上面类中的函数,你大约完成了一半的编写标准分配器。为了进行分配和删除,它具有rebind一些内存的功能(将一块内存更改为另一种类型),就地创建一个对象(基本上只是一个放置 new 的包装器)并销毁一个对象(再次,琐碎的包装器围绕析构函数调用)。当然,它使用operator newandoperator delete而不是mallocandfree就像我上面使用的那样。

于 2012-04-18T02:47:15.117 回答
9

使用placement new,您可以将已分配的内存位置传递给new 运算符。然后 new 将在给定位置构造对象而不对其自身进行分配。

编辑:

这就是它的实现方式:

int main(void){
    // get memory
    void * mem_t = SomeAllocationFunction(sizeof(SomeClass));
    // construct instance
    SomeClass* t = new(mem_t) SomeClass;

    // more code

    // clean up instance
    t->~SomeClass();
    return 0;
}
于 2012-04-18T00:53:50.177 回答
0

要调用构造函数,请使用placement new(请注意,您不能覆盖placement new)。对于删除和所有问题,FAQ 很好地解释了它。

于 2012-04-18T01:27:51.253 回答