我们需要将一些堆存储的分配和初始化分开。不幸的是,客户端代码使用
delete p;
来删除指针。如果我们可以控制删除,我们可以使用 ::operator new (sizeof(T), std::align_val_t(alignof(T)))
进行分配,然后使用放置 new
和相应的全局 ::operator delete
。但是(如果我理解正确的话)delete
可能会调用T::operator delete
,可能需要来自T::operator new
的分配,如果存在多个重载,则T::operator new
和T::operator delete
的不同可能参数之间具有复杂的优先顺序.
是否有类似
std::allocate_as_if_by_new<T>()
的东西会执行与 new T(...)
完全相同的分配,但无需初始化,或者至少保证(初始化后)delete p;
会正确地释放它?
不。 你能做的最好的事情就是使用像句柄这样的习惯用法。
句柄习惯用法是指您传递的值不是指向实际数据的真实指针。 您可以通过让句柄具有您控制的析构函数来允许删除它。
struct Interface {
virtual void DoStuff() const = 0;
virtual ~Interface() {}
};
struct Forwarder:Interface {
virtual void DoStuff() const { return pImpl->DoStuff(); }
Interface* pImpl = 0;
~Forwarder() {
/* delete pImpl using your internal mechanism */
}
};
然后从您的 API 返回
new Forwarder{ pRealObject }
。
它们
delete
Forwarder
对象,它对您的实际底层对象 pImpl
进行适当的清理。 如果它有一个虚拟函数表,您的 Forwarder
实现只会将所有内容都反弹到搞乱 pImpl
。
如果它没有虚函数表(例如,ADT 中的自由函数),您可以教这些 ADT 将参数转换为
Forwarder*
,然后使用 pImpl
代替。