我正在编写一个内存非常有限的NIOS II内核的C ++程序。由于它是一个嵌入式系统,我们也没有使用堆。由于我们在代码中添加了继承,因此我们看到malloc和free(以及相关函数)正在构建到我们的二进制文件中,从而将其大小增加了几千字节。
我们有一个纯虚拟基类,StatisticsApi和一个派生类Statistics。统计数据和它们都定义了虚拟析构函数。
我们正在使用带有fno-rtti和-fno_expections的Alteras GCC进行编译,并且还定义了我们自己的__cxa_pure_virtual()
。
仔细观察它,我们看到删除是从析构函数中调用的(因而是免费的)。这是为什么?它试图释放什么记忆?
这是析构函数的汇编程序:
0000c6b8 <_ZN7Namespace12StatisticsD0Ev>:
c6b8: defffd04 addi sp,sp,-12
c6bc: dfc00215 stw ra,8(sp)
c6c0: df000115 stw fp,4(sp)
c6c4: df000104 addi fp,sp,4
c6c8: e13fff15 stw r4,-4(fp)
c6cc: 00c000b4 movhi r3,2
c6d0: 18c74b04 addi r3,r3,7468
c6d4: e0bfff17 ldw r2,-4(fp)
c6d8: 10c00015 stw r3,0(r2)
c6dc: e13fff17 ldw r4,-4(fp)
c6e0: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c6e4: 00800044 movi r2,1
c6e8: 10803fcc andi r2,r2,255
c6ec: 1005003a cmpeq r2,r2,zero
c6f0: 1000021e bne r2,zero,c6fc <_ZN7LinCtrl12TxStatisticsD0Ev+0x44>
c6f4: e13fff17 ldw r4,-4(fp)
c6f8: 000c8e00 call c8e0 <_ZdlPv>
c6fc: e037883a mov sp,fp
c700: dfc00117 ldw ra,4(sp)
c704: df000017 ldw fp,0(sp)
c708: dec00204 addi sp,sp,8
c70c: f800283a ret
0000c710 <_ZN7Namespace12StatisticsD1Ev>:
c710: defffd04 addi sp,sp,-12
c714: dfc00215 stw ra,8(sp)
c718: df000115 stw fp,4(sp)
c71c: df000104 addi fp,sp,4
c720: e13fff15 stw r4,-4(fp)
c724: 00c000b4 movhi r3,2
c728: 18c74b04 addi r3,r3,7468
c72c: e0bfff17 ldw r2,-4(fp)
c730: 10c00015 stw r3,0(r2)
c734: e13fff17 ldw r4,-4(fp)
c738: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c73c: 0005883a mov r2,zero
c740: 10803fcc andi r2,r2,255
c744: 1005003a cmpeq r2,r2,zero
c748: 1000021e bne r2,zero,c754 <_ZN7Namespace12StatisticsD1Ev+0x44>
c74c: e13fff17 ldw r4,-4(fp)
c750: 000c8e00 call c8e0 <_ZdlPv>
c754: e037883a mov sp,fp
c758: dfc00117 ldw ra,4(sp)
c75c: df000017 ldw fp,0(sp)
c760: dec00204 addi sp,sp,8
c764: f800283a ret
0000c768 <_ZN7Namespace12StatisticsD2Ev>:
c768: defffd04 addi sp,sp,-12
c76c: dfc00215 stw ra,8(sp)
c770: df000115 stw fp,4(sp)
c774: df000104 addi fp,sp,4
c778: e13fff15 stw r4,-4(fp)
c77c: 00c000b4 movhi r3,2
c780: 18c74b04 addi r3,r3,7468
c784: e0bfff17 ldw r2,-4(fp)
c788: 10c00015 stw r3,0(r2)
c78c: e13fff17 ldw r4,-4(fp)
c790: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c794: 0005883a mov r2,zero
c798: 10803fcc andi r2,r2,255
c79c: 1005003a cmpeq r2,r2,zero
c7a0: 1000021e bne r2,zero,c7ac <_ZN7Namespace12StatisticsD2Ev+0x44>
c7a4: e13fff17 ldw r4,-4(fp)
c7a8: 000c8e00 call c8e0 <_ZdlPv>
c7ac: e037883a mov sp,fp
c7b0: dfc00117 ldw ra,4(sp)
c7b4: df000017 ldw fp,0(sp)
c7b8: dec00204 addi sp,sp,8
c7bc: f800283a ret
以下是基类的析构函数:
0000c7f0 <_ZN7Namespace15StatisticsApiD2Ev>:
c7f0: defffd04 addi sp,sp,-12
c7f4: dfc00215 stw ra,8(sp)
c7f8: df000115 stw fp,4(sp)
c7fc: df000104 addi fp,sp,4
c800: e13fff15 stw r4,-4(fp)
c804: 00c000b4 movhi r3,2
c808: 18c76204 addi r3,r3,7560
c80c: e0bfff17 ldw r2,-4(fp)
c810: 10c00015 stw r3,0(r2)
c814: 0005883a mov r2,zero
c818: 10803fcc andi r2,r2,255
c81c: 1005003a cmpeq r2,r2,zero
c820: 1000021e bne r2,zero,c82c <_ZN7Namespace15StatisticsApiD2Ev+0x3c>
c824: e13fff17 ldw r4,-4(fp)
c828: 000c8e00 call c8e0 <_ZdlPv>
c82c: e037883a mov sp,fp
c830: dfc00117 ldw ra,4(sp)
c834: df000017 ldw fp,0(sp)
c838: dec00204 addi sp,sp,8
c83c: f800283a ret
0000c840 <_ZN7LinCtrl15TxStatisticsApiD0Ev>:
c840: defffd04 addi sp,sp,-12
c844: dfc00215 stw ra,8(sp)
c848: df000115 stw fp,4(sp)
c84c: df000104 addi fp,sp,4
c850: e13fff15 stw r4,-4(fp)
c854: 00c000b4 movhi r3,2
c858: 18c76204 addi r3,r3,7560
c85c: e0bfff17 ldw r2,-4(fp)
c860: 10c00015 stw r3,0(r2)
c864: 00800044 movi r2,1
c868: 10803fcc andi r2,r2,255
c86c: 1005003a cmpeq r2,r2,zero
c870: 1000021e bne r2,zero,c87c <_ZN7Namespace15StatisticsApiD0Ev+0x3c>
c874: e13fff17 ldw r4,-4(fp)
c878: 000c8e00 call c8e0 <_ZdlPv>
c87c: e037883a mov sp,fp
c880: dfc00117 ldw ra,4(sp)
c884: df000017 ldw fp,0(sp)
c888: dec00204 addi sp,sp,8
c88c: f800283a ret
0000c890 <_ZN7Namespace15StatisticsApiD1Ev>:
c890: defffd04 addi sp,sp,-12
c894: dfc00215 stw ra,8(sp)
c898: df000115 stw fp,4(sp)
c89c: df000104 addi fp,sp,4
c8a0: e13fff15 stw r4,-4(fp)
c8a4: 00c000b4 movhi r3,2
c8a8: 18c76204 addi r3,r3,7560
c8ac: e0bfff17 ldw r2,-4(fp)
c8b0: 10c00015 stw r3,0(r2)
c8b4: 0005883a mov r2,zero
c8b8: 10803fcc andi r2,r2,255
c8bc: 1005003a cmpeq r2,r2,zero
c8c0: 1000021e bne r2,zero,c8cc <_ZN7Namespace15StatisticsApiD1Ev+0x3c>
c8c4: e13fff17 ldw r4,-4(fp)
c8c8: 000c8e00 call c8e0 <_ZdlPv>
c8cc: e037883a mov sp,fp
c8d0: dfc00117 ldw ra,4(sp)
c8d4: df000017 ldw fp,0(sp)
c8d8: dec00204 addi sp,sp,8
c8dc: f800283a ret
最后删除:
0000c8e0 <_ZdlPv>:
c8e0: 20000126 beq r4,zero,c8e8 <_ZdlPv+0x8>
c8e4: 000ebf01 jmpi ebf0 <free>
c8e8: f800283a ret
以下是NIOS II指令集的链接供参考:http://www.altera.com/literature/hb/nios2/n2cpu_nii51017.pdf
我们找到的两个解决方案/解决方法是:
将new / delete重新定义为空函数(没有堆,所以它们不应该 无论如何都要被召唤!)因此避免了对自由的呼唤。
在C ++中使析构函数未定义,这使得它们无法获取 在汇编程序中实例化。虽然编译器会抱怨 没有虚拟析构函数。
解决方法与否,为什么析构函数是免费的?它想要释放什么记忆!?!我们有其他析构函数既不是基类也不是派生类,它们不会自由调用。这就是这样的析构函数的样子:
00005194 <_ZN7Namespace16OtherClassD2Ev>:
5194: defffe04 addi sp,sp,-8
5198: df000115 stw fp,4(sp)
519c: df000104 addi fp,sp,4
51a0: e13fff15 stw r4,-4(fp)
51a4: e037883a mov sp,fp
51a8: df000017 ldw fp,0(sp)
51ac: dec00104 addi sp,sp,4
51b0: f800283a ret
000051b4 <_ZN7Namespace16OtherClassD1Ev>:
51b4: defffe04 addi sp,sp,-8
51b8: df000115 stw fp,4(sp)
51bc: df000104 addi fp,sp,4
51c0: e13fff15 stw r4,-4(fp)
51c4: e037883a mov sp,fp
51c8: df000017 ldw fp,0(sp)
51cc: dec00104 addi sp,sp,4
51d0: f800283a ret
而且,一般来说,为什么每个析构函数(D0,D1和D2)都有多个函数?
答案 0 :(得分:1)
当您使用虚拟析构函数调用对象上的delete时,它会在虚拟表中查找要调用的函数。该函数调用析构函数以及释放内存,因为只有在派生级别它才知道传递给自由函数的正确指针。
问题是编译器不知道你从不调用delete。它仍然必须创建代码,即使它可能永远不会被使用,就像任何其他虚函数一样。
尽管作为一般规则,析构函数应该在具有其他虚函数的类中是虚拟的,但这可能是一个有效的例外。在基类中保护析构函数有助于避免错误。