I have some C++ code in which I must be sure that a specific destructor is called before exiting and I was wondering whether or not it was called before a [[noreturn]] function.
So I wrote this simple dummy example
#include <cstdio>
#include <cstdlib>
class A {
char *i;
public:
A() : i{new char[4]} {}
~A() { delete[] i; }
void hello() { puts(i); }
};
int func()
{
A b;
exit(1);
b.hello(); // Not reached
}
I compiled with g++ /tmp/l.cc -S -O0
and I got this assembly
.file "l.cc"
.text
.section .text._ZN1AC2Ev,"axG",@progbits,_ZN1AC5Ev,comdat
.align 2
.weak _ZN1AC2Ev
.type _ZN1AC2Ev, @function
_ZN1AC2Ev:
.LFB18:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movl $4, %edi
call _Znam
movq %rax, %rdx
movq -8(%rbp), %rax
movq %rdx, (%rax)
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE18:
.size _ZN1AC2Ev, .-_ZN1AC2Ev
.weak _ZN1AC1Ev
.set _ZN1AC1Ev,_ZN1AC2Ev
.text
.globl func
.type func, @function
func:
.LFB24:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -8(%rbp), %rax
movq %rax, %rdi
call _ZN1AC1Ev
movl $1, %edi
call exit
.cfi_endproc
.LFE24:
.size func, .-func
.ident "GCC: (GNU) 12.2.1 20221121 (Red Hat 12.2.1-4)"
.section .note.GNU-stack,"",@progbits
There was clearly no call to the destructor.
In this stupid case it doesn't matter much, but what if I had to close a file before exiting?
Apart from the fact that terminating a program with
exit()
is generally considered bad practice, you could try the following:PS: Assuming that you aren't writing a driver, most kernels (including Microsoft Windows NT, Unix (e.g. BSD), XNU (macOS) and Linux) automatically deallocate any allocated memory as the program exits.