使用预先分配的内存和数组管理析构函数

时间:2013-05-22 23:23:37

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

您好我正在尝试使用预分配的内存创建对象和数组。例如,我有以下代码:

int * prealloc = (int*)malloc(sizeof(Test));

Test *arr = new(prealloc) Test();

测试定义如下:

class Test {
public:
    Test() {
        printf("In Constructor\n");
    }
    ~Test() {
        printf("In Destructor\n");
    }

    int val;
};

在这种情况下,如果我调用delete,它实际上会释放内存不好,b / c可能我正在使用某种类型的内存管理器,所以这肯定会引起一些问题。我在互联网上搜索,我找到的唯一解决方案是明确调用析构函数然后调用free:

arr->~Test();
free(arr);

还有其他办法吗?是否有一种方法可以调用delete并告诉它只是调用析构函数而不是释放内存?

我的第二个问题是使用数组时,就像前面的例子一样,你可以传递给新的预分配内存:

int * prealloc2 = (int*)malloc(sizeof(Test) * 10);
Test *arr2 = new(prealloc2) Test[10];

如果我调用delete[],它不仅会为数组中的每个元素调用析构函数,而且还会释放我不想要的内存。我发现它应该完成的唯一方法是遍历数组并显式调用析构函数,然后调用free。与常规无数组运算符一样,是否有一种方法可以告诉操作员只调用析构函数而不释放内存?

我注意到的一件事是数组的new运算符实际上会使用前4个字节来存储数组的大小(我只在Visual Studio中使用32位构建测试了这个)这会帮助我知道如何阵列有很多元素,但仍有一个问题。如果数组是指针数组怎么办?例如:

Test **arr2 = new Test*[10];

请有人帮我解决这些问题。

3 个答案:

答案 0 :(得分:5)

这是正常的,并期望直接调用析构函数来销毁使用placement new创建的对象。就任何其他方式而言,唯一明显的替代方法是使用一个Allocator对象(至少99%的时候,它只是一个包装新的并直接调用析构函数的包装器)。

一般来说,根本不想使用new[]。您通常希望使用operator new(或可能::operator new)分配原始内存,并使用匹配的operator delete::operator delete发布。

您可以使用placement new在该内存中创建对象,并通过直接调用析构函数来销毁它们。

答案 1 :(得分:2)

没有其他方法可以做到这一点,但显式调用析构函数为delete也会尝试释放内存。

在代码中使用预分配的内存和放置新内存应该是相当罕见的 - 一个典型的用例是当你需要/需要在固定内存地址之上映射对象时处理直接内存映射硬件接口时 - 我通常认为是一种代码味道。

如果你想调整特定类的内存管理,你最好不要使用带有自定义分配器的STL容器,或者为特定类重载operator new和delete。

答案 2 :(得分:0)

是的,这是唯一的方法。允许定义new但不定义delete存在不对称性。 [嗯,你可以做后者,但只有在new抛出异常时才会被调用(下面没有正确处理!)

您可以使用模板destroy来获得相同的结果:

class Test 
{
public:
    Test() {
        printf("In Constructor\n");
    }
    ~Test() {
        printf("In Destructor\n");
    }

    int val;
};

class Allocator
{
public:
    static void* allocate(size_t amount) { return std::malloc(amount);}
    static void unallocate(void* mem) { std::free(mem);}
    static Allocator allocator;
};

Allocator Allocator::allocator;

inline void* operator new(size_t size,  const Allocator& allocator)
{
    return allocator.allocate(size);
}


template<class T>
void destroy(const Allocator& allocator, T* object) 
{ 
    object->~T();
    allocator.unallocate(object);
}




int main()
{
    Test* t = new (Allocator::allocator) Test();

    destroy(Allocator::allocator, t);

    return 0;
}