C++ 中的智能指针
假设我们有一个基
类和一个派生
类。所以:
class base {
protected:
~base(){
//...
}
// ...
};
class derived : public base {
// ...
};
现在假设我们使用上面的类和智能指针类来编写此代码:
SmartPointer<base> bptr(new derived());
delete bptr;
我知道它会通过调用派生的析构函数来防止对派生对象进行切片>,但是它怎么知道要这样做呢?存储在智能指针中的引用不应该是base*
类型的引用吗?它是否遍历某种层次结构树,将该指针强制转换为衍生*
,然后调用删除?还是还有什么我不知道的事情?
该实现据称是线程安全的、非侵入式的和引用计数的。
是,您看到的类与我正在测试的类类似。显然有一种方法可以通过这些给定的类来做到这一点。我在上面的问题中提到了关于如何实现的主要想法,但我不确定这样的实现将如何工作。
Say we have a base
class and a derived
. So:
class base {
protected:
~base(){
//...
}
// ...
};
class derived : public base {
// ...
};
And now say that we have this code using the above classes with a smart pointer class:
SmartPointer<base> bptr(new derived());
delete bptr;
I understand that it would prevent slicing of the derived
object by calling the destructor of derived
, but how does it know to do that? Wouldn't the reference stored in the smart pointer be that of type base*
? Does it traverse some kind of hierarchy tree, cast that pointer to derived*
and then call delete? Or is there some other thing that I don't know about?
The implementation is supposedly threadsafe, non-intrusive, and reference counting.
YES, the classes that you see are akin to the ones that I'm testing against. There is apparently a way to do this with THESE GIVEN classes. The main idea as to how is mentioned in my question above, but I'm not sure as to how one such an implementation would work.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
首先,就目前的情况来看,代码将无法工作。
base
的析构函数至少必须受到protected
(或者派生类是基类的友元)。private
析构函数意味着编译器不允许您为派生类编写析构函数。现在,假设您有一个受保护的析构函数...(请记住,如果您设计要扩展的类,请提供一个公共虚拟析构函数或一个受保护的析构函数)非虚拟!)一切都取决于
SmartPointer
的实现,特别是std::shared_ptr
(或boost对应的boost::shared_ptr
)能够干净地管理这种情况。该解决方案出于破坏目的执行某种类型的部分类型擦除。基本上,智能指针有一个模板化构造函数,它接受任何可以分配给基指针的指针,但因为它是模板化的,所以它知道具体类型。此时,它存储一个合成的删除器函数,该函数将调用适当的析构函数。为简单起见,使用
std::function
:该代码仅用于展示,必须针对生产进行调整(在哪里存储
function
、引用计数... ),但这足以让您了解:在唯一已知对象确切类型的函数中(创建智能指针时),您创建一个包装器,它将调用您需要的析构函数的确切版本(提供一些类型擦除的缺陷),然后将其保留,当您需要删除
对象时,调用它而不是delete
运算符。这也可以用于管理需要调用特殊方法而不是删除的其他资源:
同样,在准备好此生产之前应该有相当多的工作。
可以消除对用于简化擦除的
std::function
的依赖。在简单的情况下(智能指针仅支持使用new
分配内存并使用delete
释放内存),则只需提供一个deleter
基类使用单个虚拟operator()(void*)
,然后将现有的delete_deleter
重构为覆盖的
。如果您需要处理一般情况(保存任何类型的资源),那么不值得付出努力,只需使用deleter
的模板化派生类使用当前实现的operator()(void*)std::function
或boost::function
即可。First thing is that as it stands the code will not work. The destructor of
base
must be at the very leastprotected
(or derived classes be friends of the base). Aprivate
destructor means that the compiler will not allow you to write the destructor for the derived classes. Now, assuming that you have aprotected
destructor... (Rembember, if you design a class to be extended, provide either a public virtual destructor or a protected non-virtual!)All depends on the implementation of the
SmartPointer
, in particularstd::shared_ptr
(or the boost counterpartboost::shared_ptr
) are able to manage that situation cleanly. The solution performs some sort of partial type erasure of the type for destruction purposes. Basically, the smart pointer has a templated constructor that accepts any pointer that can be assigned to abase
pointer, but because it is templated it knows the concrete type. At that point it stores a syntheticdeleter
function that will call the appropriate destructor.For simplicity, using
std::function
:The code is for exhibition only, it would have to be tweaked for production (where to store the
function
, reference counting...), but it is enough to give you the idea: in the only function where the exact type of the object is known (when creating the smart pointer), you create a wrapper that will call the exact version of the destructor that you need (providing some short of type erasure), then just leave it around and when you need todelete
the object call it instead of thedelete
operator.This can also be used to manage other resources that require calling a special method instead of
delete
:Again there should be quite a lot of work before making this production ready.
Dependency on
std::function
which is used to simplify the erasure, can be eliminated from the problem. In the simple case (only memory allocated withnew
and freed withdelete
is supported in the smart pointer), then just provide adeleter
base class with a single virtualoperator()(void*)
, and then refactor the existingdelete_deleter
into templated derived classes fromdeleter
that overrideoperator()(void*)
with the current implementation. If you need to go for the general case (hold any type of resource) it is not worth the effort, just usestd::function
orboost::function
.首先,你的析构函数不应该是私有的,否则根本无法编译。其次,如果您使用“智能指针”,您可能根本不应该手动删除指针(虽然我不知道您正在使用什么实现,但这对我来说很奇怪)。
无论如何,如果您好奇当通过指向基类的指针删除对象时如何调用派生类的析构函数,答案就是多态性。但是您的析构函数缺少
virtual
声明,现在您的代码不会调用派生类的析构函数。大多数 C++ 实现是通过虚拟表来实现这一点的。
Well first of all, your destructor shouldn't be private or that won't compile at all. Secondly, if you're using a "smart pointer", you probably should not be deleting the pointer by hand at all (I don't know what implementation you're using though, but this strikes as odd to me).
Anyways if you're curious how the derived class' destructor gets called when the object is deleted through a pointer to the base class, the answer is polymorphism. But you're missing
virtual
declaration from your destructor, right now your code would not call the derived class' destructor.How most C++ implementations implement this is through a virtual table.
如果您使用任何 boost 智能指针或其他不是您的
Base
类的friend
的指针,那么此代码将无法编译,因为Base< 的析构函数/code> 类是
protected
(与其他独立于Base
类的private
相同)。现在让我们假设您将
SmartPointer
设为Base
的友元。在这种情况下,代码可以工作,但它不会调用Derived
的析构函数,而是调用Base
的析构函数,因为这里您的Base
类不是多态的。您应该将Base
的destrucotr 声明为virtual
。在最后一种情况下,当您的智能指针被删除时,将调用正确的析构函数。If you using any of boost smart pointers or some other which is not
friend
of yourBase
class, then this code wouldn't compile, because destructor ofBase
class isprotected
(which is same asprivate
for other independent fromBase
classes).Now let's consider that you make
SmartPointer<Base>
friend ofBase
. This case the code will work, but it wouldn't call destructor ofDerived
but destructor ofBase
, because here yourBase
class is not polymorphic. You should declare destrucotr ofBase
asvirtual
. In last case the correct destructor will be called when your smart pointer is deleted.该程序无效。
1)base的dtor是私有的
2)base的dtor不是虚拟的
来回答你的问题:你需要更正#1和#2。 然后将使用动态调度来调用 dtor(这将以与构造相反的顺序调用每个 dtor)。
如果不进行这些更正,
SmartPointer
能够知道在此示例中以定义的方式调用派生的 dtor 的唯一方法是SmartPointer
是否过于聪明(或使用起来很乏味) )。this program is invalid.
1) the dtor of base is private
2) the dtor of base is not virtual
to answer your question: you need to correct #1 and #2. then the dtor will be called using dynamic dispatch (which will invoke each dtor in reverse order of construction).
without making those corrections, the only way
SmartPointer
could know to call derived's dtor in this example, and in a defined manner, is ifSmartPointer
was overly clever (or tedious to use).您的基类析构函数需要是虚拟的,以确保在通过基指针删除时调用派生类的析构函数。
有关虚拟析构函数的维基百科条目
Your base class desctructor needs to be virtual to ensure that destructor of derived class is called when deleting via base pointer.
Wikipedia entry on virtual desctructors