删除具有受保护析构函数的对象
Delete an object with a protected destructor
我必须为类编写一个共享指针,它必须做的许多其他事情之一是确保它可以删除它所指向的对象。
如何编写一个解决方案来处理具有受保护的析构函数的对象?
此外,如果对象是使用placement new创建的,则我不应该在对象上调用delete
,因为该空间可能仍在使用中(delete
调用是否有效?)。我怎样才能发现这种情况?
规范的相关部分:
void reset();
智能指针设置为指向空指针。当前指向的对象的引用计数(如果有)将递减。Sptr();构造一个指向空指针的智能指针。
template <typename U> Sptr(U *);
构造一个指向给定对象的智能指针。引用计数已初始化为1。
Sptr(const Sptr &);
template <typename U> Sptr(const Sptr<U> &);
引用计数递增。如果U*不能隐式转换为T*,这将导致语法错误。请注意,必须同时提供普通复制构造函数和成员模板复制构造函数才能正常操作。
代码的调用方式:
Sptr<Derived> sp(new Derived);
char *buf = (char *) ::operator new(sizeof(Sptr<Base1>));
Sptr<Base1> &sp2 = *(new (buf) Sptr<Base1>());
sp2 = sp;
sp2 = sp2;
sp.reset();
sp2.reset();
::operator delete(buf);
Base1
保护了一切。
使析构函数非公共的全部目的是防止对象被任意销毁。没有什么好办法绕过这一点。(即使有一个通用的方法,它也不是一个好的方法,因为它需要打破封装才能做到这一点。)
如果希望某个对象被除其本身之外的其他类销毁,请将析构函数设为公共的。如果不这样做,那么指针类也将无法销毁对象。
或者,您可以使指针类成为您希望它使用的任何类的朋友。但这在很多方面都很丑陋,尤其是它相当武断地限制了你可以使用的有效对象类型
与引用计数器一起存储指向将删除对象的函数的指针("deleter")。您将在智能指针的模板化构造函数中实例化deleter,在那里您知道派生类型。这里有一个极其天真的伪代码:
template<class T> void DefaultDeleter(void *p) { delete static_cast<T*>(p); }
struct ref_counter {
int refs;
void *p;
void (*d)(void *);
};
template<class T> class Sptr {
/* ... */
template <typename U> Sptr(U *p)
{
_c = new ref_counter;
_c->refs = 1;
_c->p = static_cast<void*>(p);
_c->d = &DefaultDeleter<U>;
_p = p;
}
T *_p;
ref_counter *_c;
};
当refs
降至零时,调用(*_c->d)(_c->p)
来销毁指向的对象。
我当然假设Base
的析构函数是受保护的,而Derived
的析构因子是公共的,否则这个练习就没有意义了。
注意:这就是std::shared_ptr
可以安全地与具有非虚拟析构函数的基类一起使用的原因。
您的类可以接受一个deleter函子,然后该函子将负责释放对象。通过这样做,你可以将访问析构函数的问题转移到使用你的类的人身上。:)
撇开玩笑不谈,如果调用者知道如何创建类的实例,那么他们也应该知道如何销毁这些实例。
这也将提供一种解决与放置CCD_ 12相关联的问题的方法。
阅读您的规范更新后,我可以告诉您,没有办法正确实现这一点,因为:
- 指针无法区分新大小写和放置新大小写。您的委托人唯一能做的就是调用
delete p
。这是而不是在放置新情况下正确的做法,尽管它在您的示例中可能会起作用,因为缓冲区恰好是正确的大小,并且分配了new
- 正如其他答案中所解释的,对于您的删除程序来说,没有好的方法来绕过受保护的析构函数问题
通过在构造函数中添加自定义deleter的可能性,可以解决这两个问题。
编辑:这就是添加自定义删除程序的方法:
template <typename U> Sptr(U *, std::function<void(T*)> &&deleter);
构造一个指向给定对象的智能指针。这个引用计数被初始化为1。自定义删除程序称为当引用计数达到零时,原始指针指向例子
- 什么时候调用组成单元对象的析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- C++析构函数调用两次,堆栈分配的复合对象
- 如何从 Gtk::窗口调用派生对象的析构函数
- 为什么数组中对象的析构函数在被另一个对象替换时不被调用?
- 为什么为未删除的对象调用析构函数?
- 对象的构造函数和析构函数
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- C++使用函数对象的线程,如何调用多个析构函数而不是构造函数?
- 从未调用shared_ptr对象的析构函数
- 是否可以在其析构函数中使用指向已销毁对象的指针?
- 使用私有析构函数删除动态分配的对象
- C++ std::线程调用方法,从对象原因到调用此类的析构函数
- 为什么在这里调用析构函数,以及在调用该对象析构函数后如何调用对象成员函数?
- 对象析构函数在多线程处理时不断被调用,但该对象并未超出范围
- C++包含包含指针的对象的对象析构函数
- Objective-C++C++对象析构函数
- 结构对象析构函数
- 在Exit()时调用基本对象析构函数