1

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

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

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

其中 test 定义如下:

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

    int val;
};

在这种情况下,如果我调用 delete 它实际上会释放坏的内存,b/c 也许我正在使用某种类型的内存管理器,所以这肯定会导致一些问题。我在互联网上搜索,我发现的唯一解决方案是显式调用析构函数,然后免费调用:

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

还有另一种方法可以做到这一点吗?有没有办法调用 delete 并告诉它只调用析构函数而不释放内存?

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

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

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

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

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

有人可以帮我解决这些问题吗?

4

3 回答 3

5

直接调用析构函数来销毁您使用placement new 创建的对象是很正常的。至于任何其他的做事方式,唯一明显的替代方案是使用分配器对象(至少 99% 的时间,它只是放置 new 并直接调用析构函数的包装器)。

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

您在该内存中创建具有新位置的对象,并通过直接调用析构函数来销毁它们。

于 2013-05-22T23:30:11.963 回答
2

除了显式调用析构函数之外别无他法,因为 delete 也会尝试释放内存。

在您的代码中使用带有放置 new 的预分配内存应该是相当少见的 - 一个典型的用例是当您想要/需要在固定内存地址上映射对象时处理直接内存映射的硬件接口 - 并且是我通常会考虑代码气味。

如果您想调整特定类的内存管理,最好使用带有自定义分配器的 STL 容器或为该特定类重载运算符 new 和 delete。

于 2013-05-22T23:29:44.130 回答
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;
}
于 2013-05-22T23:59:12.637 回答