我开始阅读模板,我发现智能指针使用双模板,如下所示:
template <class T>
class myclass
{
public:
template <class U>
myclass(U* q) { /* ... */ }
};
Run Code Online (Sandbox Code Playgroud)
那是什么意思?我知道模板功能会推断U,如
myclass(new whatever(3));
Run Code Online (Sandbox Code Playgroud)
U会在哪里whatever*.那是什么T?U和之间有什么关系T?
我糊涂了...
上面的示例代码与T和之间没有任何关系U.
一个是传递给类模板的类型参数myclass,另一个是传递给构造函数的推导类型.
但是,你发现它(std::shared_ptr可能)它会变得更有趣.
现在,std::shared_ptr构造函数的主体强制要求U是一个后代类型T.该构造允许您创建一个std::shared_ptr<Base>从Derived*而知道它正在从一个构建在构造函数中Derived*.
我们为什么要这样?毕竟,a Derived*可以转换为Base*构造函数外部,所以为什么不采取T*(又名Base*)?
好吧,一个std::shared_ptr<T>是捆绑在一起的3件事.它是一个T*参考计数器和一个清理功能("删除器").
当引用计数减少到0时,将调用清除函数.默认情况下,清理函数调用指向对象的析构函数.
但是哪个析构函数?好吧,调用的析构函数是基于类型的U,而不是 T.在构造时,编写一个知道静态类型的销毁函数U.这个破坏功能被带到原始的所有副本shared_ptr<T>,所以即使它被远远地摧毁它仍然会调用~U而不是~T.
如果T有一个virtual ~T()这没有做太多(事实上,相同的comdat折叠或类似的技术将使它什么都不做),但如果它有一个非虚拟析构函数,shared_ptr将调用正确的析构函数(假设类型实际上U不是一些衍生类型U).
shared_ptr 由于其他原因需要存储销毁功能(您可以传递自定义销毁功能),因此这不会产生很大的开销.