C ++:将类实例存储在已分配的内存中

时间:2010-12-08 14:53:40

标签: c++ pointers malloc

我有一个班级A。我正在使用的一些库为我分配给定量的内存,sizeof A,并返回一个指向它的void指针。

A* pObj = (A*) some_allocator_im_forced_to_use( sizeof A );

现在如何在刚分配的内存中创建A的新实例?

我尝试过:

*pObj = A();

但这不起作用 - 析构函数在A的构造函数之后被调用。

6 个答案:

答案 0 :(得分:8)

您可以使用展示位置新内容:

A* pObj = new ( some_allocator_im_forced_to_use( sizeof( A ) ) ) A;

这会在函数A返回的位置构造一个新的some_allocator_im_forced_to_use实例。此函数需要返回一个void*,指向适当的内存,并为相关实现上的A对象进行适当的对齐。

您可能需要手动为此对象手动调用析构函数,因为您将无法使用通常的delete pObj来销毁它。

pObj->~A();
// Call custom allocator's corresponding deallocation function on (void*)pObj

为了正确销毁对象并释放内存,您可以考虑将shared_ptr与自定义删除器一起使用。

答案 1 :(得分:3)

使用展示位置新功能:

new (pObj) A;

您还需要以不同方式销毁对象,因为delete假设(错误地)您使用普通的new创建了对象:

pObj->~A();
some_deallocator_im_forced_to_use( pObj );

答案 2 :(得分:2)

您需要'放置新'

请参阅此答案:What uses are there for "placement new"?

答案 3 :(得分:1)

答案 4 :(得分:1)

有些人主张安置新的。

这很危险,到目前为止两个使用示例已经省略了关键细节,例如包括<new>标题,限定调用如::new ...,以及如何清理。

安全的解决方案是为您的类或从您的类派生的类定义自定义分配和释放函数。下面的例子显示了后者。请注意,虚拟析构函数仅用于支持类派生;如果你没有得到,你就不需要它。

#include <stddef.h>
#include <iostream>

void* some_allocator_im_forced_to_use( size_t size )
{
    std::cout << "Allocated " << size << " bytes." << std::endl;
    return ::operator new( size );
}

void some_deallocator_im_forced_to_use( void* p, size_t size )
{
    std::cout << "Deallocated " << size << " bytes." << std::endl;
    ::operator delete( p );
}

struct A
{
    int x_;
    A(): x_( 42 ) {}
    virtual ~A() {}
};

struct CustomAllocedA
    : A
{
    void* operator new( size_t size )
    {
        return some_allocator_im_forced_to_use( size );
    }

    void operator delete( void* p, size_t size )
    {
        some_deallocator_im_forced_to_use( p, size );
    }
};

int main()
{
    A* const    p    = new CustomAllocedA;

    std::cout << p->x_ << std::endl;
    delete p;
}

重要说明:虽然这本身就是“安全的”,虽然这个特殊的例子是安全的,但你的代码的安全性最终取决于你的自定义分配器返回指向正确对齐的内存的指针。

干杯&amp;第h。,

答案 5 :(得分:0)

如果您的分配器遵循std::allocator模型,它应该有几种方法:

  • allocate
  • construct
  • destroy
  • deallocate

它们几乎是不言自明的,重要的是你有责任给它们打电话:

  • 按正确的顺序
  • 并且不会忘记任何

或者你会得到UB或泄漏。

然而,我有点惊讶的是,只有分配器需要大小,通常它还需要对象的对齐,除非只是使用目标上可能的最大对齐,而不管要分配的对象。