英文:
C++ [[noreturn]] function call and destructors
问题
这里是代码部分的翻译:
我有一些C++代码,其中我必须确保在退出之前调用特定的析构函数,我想知道在调用[[noreturn]]函数之前是否已经调用了它。
所以我写了这个简单的示例
```cpp
#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
}
我使用g++ /tmp/l.cc -S -O0
编译后,得到了以下汇编代码
.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
显然没有调用析构函数。
在这种愚蠢的情况下,这不太重要,但如果我需要在退出之前关闭一个文件呢?
<details>
<summary>英文:</summary>
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
```cpp
#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?
答案1
得分: 3
除了使用 exit()
终止程序通常被认为是不良实践之外,你可以尝试以下方法:
int func()
{
{
A b;
/* ... */
} // 离开作用域 => 销毁 b
exit(1);
}
PS:假设你不是在编写驱动程序,大多数内核(包括 Microsoft Windows NT、Unix(如 BSD)、XNU(macOS)和 Linux)在程序退出时会自动释放分配的内存。
英文:
Apart from the fact that terminating a program with exit()
is generally considered bad practice, you could try the following:
int func()
{
{
A b;
/* ... */
} // Leaving scope => destructing b
exit(1);
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论