您好我正在尝试使用预分配的内存创建对象和数组。例如,我有以下代码:
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];
请有人帮我解决这些问题。
答案 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;
}