堆栈分配对象的 C++ 虚拟析构函数内联

标签 c++ inline

在隐式销毁堆栈分配对象的情况下,是否允许编译器内联虚拟析构函数?

我知道“删除”操作必须通过虚拟函数表调用虚拟析构函数(例如,它不能内联),因为它无法知道指针引用的确切类。

但是当在堆栈上分配对象时,编译器知道确切的类。所以我认为可以自由地内联隐式破坏,因为它可以看到该类的实际析构函数。如果不允许编译器这样做,那为什么不呢?什么情况下可以将析构函数重写为与编译器所知不同的东西?

最佳答案

是的,在这种情况下编译器可以内联虚拟析构函数。让我们考虑一个代码示例:

#include <iostream>

int global = 0;

class A {
public:
  virtual void foo() { std::cout << "A" << std::endl; }
  virtual ~A() { ++global; }
};

class B : public A {
public:
  virtual void foo() { std::cout << "B" << std::endl; }
  virtual ~B() { --global; }
};

int main() {
  {
    B b[5];
    b[0].foo();
  }
  std::cout << "global: " << global << std::endl;
  return 0;
}

https://godbolt.org/g/PWEVW8

如您所见,带有 -O3 优化的 clang 3.8 将永远不会生成类代码(带有 -O3 的 gcc 6.1 将生成 B 类,但无论如何都会内联析构函数):

main:                                   # @main
        pushq   %r14
        pushq   %rbx
        pushq   %rax
        movl    std::cout, %edi
        movl    $.L.str.2, %esi
        movl    $1, %edx
        callq   std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        movq    std::cout(%rip), %rax
        movq    -24(%rax), %rax
        movq    std::cout+240(%rax), %rbx
        testq   %rbx, %rbx
        je      .LBB0_9
        cmpb    $0, 56(%rbx)
        je      .LBB0_3
        movb    67(%rbx), %al
        jmp     .LBB0_4
.LBB0_3:
        movq    %rbx, %rdi
        callq   std::ctype<char>::_M_widen_init() const
        movq    (%rbx), %rax
        movl    $10, %esi
        movq    %rbx, %rdi
        callq   *48(%rax)
.LBB0_4:                                # %_ZNKSt5ctypeIcE5widenEc.exit2
        movsbl  %al, %esi
        movl    std::cout, %edi
        callq   std::basic_ostream<char, std::char_traits<char> >::put(char)
        movq    %rax, %rdi
        callq   std::basic_ostream<char, std::char_traits<char> >::flush()
        movl    std::cout, %edi
        movl    $.L.str, %esi
        movl    $8, %edx
        callq   std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        movl    global(%rip), %esi
        movl    std::cout, %edi
        callq   std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        movq    %rax, %r14
        movq    (%r14), %rax
        movq    -24(%rax), %rax
        movq    240(%r14,%rax), %rbx
        testq   %rbx, %rbx
        je      .LBB0_9
        cmpb    $0, 56(%rbx)
        je      .LBB0_7
        movb    67(%rbx), %al
        jmp     .LBB0_8
.LBB0_7:
        movq    %rbx, %rdi
        callq   std::ctype<char>::_M_widen_init() const
        movq    (%rbx), %rax
        movl    $10, %esi
        movq    %rbx, %rdi
        callq   *48(%rax)
.LBB0_8:                                # %std::ctype<char>::widen(char) const [clone .exit]
        movsbl  %al, %esi
        movq    %r14, %rdi
        callq   std::basic_ostream<char, std::char_traits<char> >::put(char)
        movq    %rax, %rdi
        callq   std::basic_ostream<char, std::char_traits<char> >::flush()
        xorl    %eax, %eax
        addq    $8, %rsp
        popq    %rbx
        popq    %r14
        retq
.LBB0_9:
        callq   std::__throw_bad_cast()

        pushq   %rax
        movl    std::__ioinit, %edi
        callq   std::ios_base::Init::Init()
        movl    std::ios_base::Init::~Init(), %edi
        movl    std::__ioinit, %esi
        movl    $__dso_handle, %edx
        popq    %rax
        jmp     __cxa_atexit            # TAILCALL

global:
        .long   0                       # 0x0

.L.str:
        .asciz  "global: "

.L.str.2:
        .asciz  "B"

关于堆栈分配对象的 C++ 虚拟析构函数内联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37492265/

相关文章:

c++ - 如何从整个代码的函数中打开文件?

c++ - 模板是如何工作的,它们总是内联的吗?

javascript - 如何在没有内联样式的情况下使用 Javascript 在表单上突出显示颜色?

c++ - 头文件和源文件中的内联函数

javascript - 如何使用 Javascript 平滑地平移内联 SVG

带小数点的 C++ 后缀求值

C++ Array of 120 ob​​jects with constructor + parameters, header- + sourcefile, no pointers please!

C++如何将字符串中的所有 `\`变成 `/`?

html - 图像不显示内联

c++ - OpenGL 中的阴影贴图