关于虚析构函数和shared_ptr的错误记录
起因
最近在写那个串口调试工具的替代品. 然后有个地方,感觉很麻烦,想了几天,决定用cpp的多态来解决.说到cpp的多态,就没法脱离引用或者是指针,我会用的就是shared_ptr了,自动计数指针!
经过
然后我就把它两结合了起来,发现结果是错误的,然后就开始调试,试了一段时间,发现析构函数根本就没有被调用.我将代码进行抽象如下:
#include <memory>
class Base{
//is the public: necessary
public:
//(1)
//virtual Base() {}
};
class Sub: public Base{
public:
~Sub() {
//do something
}
}
void foo() {
Base *b=new Sub();
shared_ptr<Base> pb(b);
//(2)
//shared_ptr<Base> pb(new Sub());
}
int main() {
foo();
return 0;
}
几次实验之后发现有两种解决方法:
- 在Base类中声明析构函数为
virtual
,即注释(1)内容 - 直接将new出的指针传入
shared_ptr<Base>
的构造函数
其中第一种方法,本人可以理解,应为基类的指针析构时没有调用动态类型的析构函数.但第二种就不理解了,难道传入的其实不是Base *
类型?
结果
之后上Compiler Explorer上查了下汇编,做了下差分,果不其然:
%PATH%>diff a b
1,7d0
< Sub::~Sub() [base object destructor]:
< push rbp
< mov rbp, rsp
< mov QWORD PTR [rbp-8], rdi
< nop
< pop rbp
< ret
11c4
< sub rsp, 16
---
> sub rsp, 32
14,15c7,9
< mov rdx, rax
< lea rax, [rbp-16]
---
> mov QWORD PTR [rbp-8], rax
> mov rdx, QWORD PTR [rbp-8]
> lea rax, [rbp-32]
18,19c12,13
< call std::shared_ptr<Base>::shared_ptr<Sub, void>(Sub*)
< lea rax, [rbp-16]
---
> call std::shared_ptr<Base>::shared_ptr<Base, void>(Base*)
> lea rax, [rbp-32]
...
至于std::shared_ptr<Base>::shared_ptr<Sub,void>
到底是什么,就让它成为又一个
吧 xp