C++放置new、继承和析构函数
C++ placement new, inheritance and destructor
研究员
在类层次结构上使用placement new时,基类必须执行取消分配。否则,基类析构函数将在取消分配的对象上调用。我希望能够从派生类中执行取消分配。所以我对想法和建议持开放态度!(注意:我不适合放置新的,但我想有自定义的内存管理,而不是新的/删除(。
请在下面找到一个代码示例:
#include <cstdint>
#include <cstdio>
#include <new>
class CParent
{
public :
CParent() {
printf("CParent()n");
}
virtual ~CParent() {
printf("~CParent()n");
}
};
class CAllocator
{
private :
void Free(uint8_t *buffer) {
printf("CAllocator::Free(%p)n", buffer);
delete [] buffer;
}
class CChild : public CParent
{
public :
CChild(CAllocator &allocator, uint8_t *buffer)
: mAllocator(allocator), mBuffer(buffer)
{
printf("CChild()n");
}
~CChild() {
printf("~CChild()n");
mAllocator.Free(mBuffer);
}
private :
CAllocator &mAllocator;
uint8_t *mBuffer;
};
public :
CParent *Alloc() {
uint8_t *buffer = new uint8_t[sizeof(CChild)];
printf("CAllocator::Alloc() = %pn", buffer);
return new (buffer) CChild(*this, buffer);
}
};
int main()
{
CAllocator allocator;
CParent *object = allocator.Alloc();
// NB: Can't do `delete object` here because of placement-new
object->~CParent();
return 0;
}
它给出以下输出:
CAllocator::Alloc() = 0x2001010
CParent()
CChild()
~CChild()
CAllocator::Free(0x2001010)
~CParent()
所以~CParent()
是在内存释放后调用的。。。非常感谢你的帮助!
您将以下概念混合在一起,这让我觉得您不清楚它们应该是什么:
- 基类/派生类析构函数
- 放置
new
运算符 - 内存分配和释放
当您使用普通的旧operator new
来分配对象时,会发生两件事:
- 已为对象分配内存
- 调用对象的构造函数(对于具有构造函数的类(
当您对operator new
返回的指针调用operator delete
时,会发生两件事:
- 调用对象的析构函数
- 内存已解除分配
当您使用放置new
操作符时,您必须:
- 在调用放置
new
操作符之前分配内存 - 在对
new
的调用中使用预先分配的内存。调用类的构造函数来初始化对象
对于此类对象,您必须:
- 显式调用析构函数
- 使用与内存分配方式匹配的方法取消分配内存。如果使用
operator new char[size];
分配内存,请使用delete [] ptr;
取消分配内存。如果使用malloc(size)
分配内存,请使用free(ptr)
取消分配内存
为了保持你的代码干净,你应该分开:
- 内存分配和释放的责任
- 调用构造函数和析构函数的责任
在您发布的代码中,类CChild
似乎是不干净的。目前还不清楚它是面向用户的类还是帮助您管理内存的辅助类。
如果你想让它成为一个面向用户的类,我会将代码重构为:
#include <cstdint>
#include <cstdio>
#include <new>
class CParent
{
public :
CParent() {
printf("CParent()n");
}
virtual ~CParent() {
printf("~CParent()n");
}
};
class CChild : public CParent
{
public :
CChild()
{
printf("CChild()n");
}
~CChild() {
printf("~CChild()n");
}
private :
};
class CAllocator
{
public :
void Free(uint8_t *buffer) {
printf("CAllocator::Free(%p)n", buffer);
delete [] buffer;
}
uint8_t *Alloc(size_t size) {
uint8_t *buffer = new uint8_t[size];
printf("CAllocator::Alloc() = %pn", buffer);
return buffer;
}
};
int main()
{
CAllocator allocator;
uint8_t *buffer = allocator.Alloc(sizeof(CChild));
CParent* object = new (buffer) CChild;
object->~CParent();
allocator.Free(buffer);
return 0;
}
如果您想将CChild
用作管理内存的辅助类,那么您必须做的第一件事就是确保CAllocator::Alloc()
和CAlloctor::Free()
是对称的。由于Alloc()
返回指向CParent
的指针,您需要更改Free()
以接受指向CParent
的指针,并对其进行正确的处理
#include <cstdint>
#include <cstdio>
#include <new>
class CParent
{
public :
CParent() {
printf("CParent()n");
}
virtual ~CParent() {
printf("~CParent()n");
}
};
class CAllocator
{
private :
class CChild : public CParent
{
public :
CChild(uint8_t *buffer) : mBuffer(buffer)
{
printf("CChild()n");
}
~CChild() {
printf("~CChild()n");
// The object has ownership of the buffer.
// It can deallocate it.
delete [] mBuffer;
}
private :
uint8_t *mBuffer;
};
public :
// Make Alloc and Free symmetric.
// If Alloc() returns a CParent*, make sure Free()
// accepts the same value and does the right thing
// with it.
CParent *Alloc() {
uint8_t *buffer = new uint8_t[sizeof(CChild)];
printf("CAllocator::Alloc() = %pn", buffer);
// Transfer the ownership of buffer to CChild
return new (buffer) CChild(buffer);
}
void Free(CParent* object) {
printf("CAllocator::Free(%p)n", object);
object->~CParent();
}
};
int main()
{
CAllocator allocator;
CParent *object = allocator.Alloc();
allocator.Free(object);
return 0;
}
相关文章:
- C++ std::vector 中的虚拟析构函数继承
- 继承的类析构函数
- 抽象类析构函数与继承"Shutdown"函数
- C++虚拟继承、虚拟析构函数和 dynamic_cast<void*>
- 如果不手动完成,子类是否继承父类的析构函数?
- 从 std::streambif 继承时不兼容析构函数编译器警告
- 多重继承析构函数调用他自己和父析构函数?c++
- 为什么我在使用组合而不是继承时得到 C4624(无法访问基类析构函数)
- 抽象基类中的析构函数保护不会在 C++ 中继承
- C++继承和构造函数、析构函数
- 从 STL 容器继承并删除"新"运算符以防止由于缺少虚拟析构函数而导致未定义的行为是否有意义?
- 虚拟继承中的析构函数
- 复制、移动、交换、赋值和析构函数的C++继承?我需要哪个
- 在不使用虚拟析构函数的情况下删除继承的对象时中止
- C++析构函数继承
- C++非抽象析构函数继承
- 构造函数和析构函数继承
- C++析构函数-继承上下文中的显式调用
- 非虚拟平凡析构函数 + 继承
- C++构造函数/析构函数继承