2010-12-08 50 views
3

我有一个类A。我正在使用的一些库为我分配了一定量的内存,sizeof A,并返回一个void指针。C++:在分配的内存中存储类实例

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

现在我怎么可以创建A一个新的实例,在刚刚分配的内存?

我有尝试过:

*pObj = A(); 

但这并没有工作 - 析构函数得到了A的构​​造

回答

8

您可以使用新的位置后立即叫:

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

这会在函数some_allocator_im_forced_to_use返回的位置构造一个新的A实例。这个函数需要返回一个void*,指向足够的内存,这个内存在正在讨论的实现中的A对象上适当对齐。

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

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

为了正确销毁对象,释放你可以考虑使用一个shared_ptr与定制删除的记忆。

3

使用放置新:

new (pObj) A; 

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

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

如果您分配如下std::allocator模型应当有几种方法:

  • allocate
  • construct
  • destroy
  • deallocate

他们是非常不言自明的,最重要的是,你有责任美其名曰:

  • 按照正确的顺序
  • ,不要忘了任何

或者你会得到UB或泄漏。但是我有点惊讶,只有大小是你的分配器所需要的,通常它还需要对象的对齐,除非是简单地使用目标上可能的最大对齐方式,而不管对象是否被分配。

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; 
} 

重要提示:虽然这本身就是“安全”,尽管这个特殊的例子是安全的,代码的安全最终取决于您的自定义分配器返回一个指针,以正确对齐的内存。

干杯&心连心,

+0

+1覆盖新的运营商是绝对比使用放置新的更好的主意。 – 2010-12-08 16:03:15