为简单的 `std::unique_ptr` 使用生成的代码大小?

问题描述 投票:0回答:1

假设我有一个函数消耗

std::unique_ptr
:

void foo(std::unique_ptr<int>);

我这样称呼:

foo(std::make_unique<int>(0));

与此功能比较:

void foo(int*);

我这样称呼:

foo(new int{0});

我希望代码生成器几乎完全相同(尽管我认为可能存在关于传递或不传递寄存器的烦人的 ABI 问题)。尽管如此,我仍在想象

std::make_unique
调用
new int{0}
,移动构造
foo
的参数,所有这些我认为都会得到优化,包括
nullptr
签入
~unique_ptr()

然而,幸福的道路是:

test():
        push    rbx
        sub     rsp, 16
        mov     edi, 4
        call    operator new(unsigned long)@PLT
        mov     dword ptr [rax], 0
        mov     qword ptr [rsp + 8], rax
        lea     rdi, [rsp + 8]
        call    foo(std::unique_ptr<int, std::default_delete<int>>)@PLT
        mov     rdi, qword ptr [rsp + 8]
        test    rdi, rdi
        je      .LBB0_3
        mov     esi, 4
        call    operator delete(void*, unsigned long)@PLT
.LBB0_3:
        add     rsp, 16
        pop     rbx
        ret

new
版本相比,优化为:

test():
        push    rax
        mov     edi, 4
        call    operator new(unsigned long)@PLT
        mov     dword ptr [rax], 0
        mov     rdi, rax
        pop     rax
        jmp     foo(int*)@PLT

https://godbolt.org/z/PbsxjTdKW

如果我使用

std::unique_ptr<int, Nop>
(使删除器消失),我会得到更像我期望的东西:

https://godbolt.org/z/r4PcGn78E

为什么优化器不能看透参数的传输并优化掉对

delete
的任何调用?

一切都优化后,我想象我们:

  1. 致电

    new int(0)
    (在
    std::make_unique
    内)。这可能会抛出异常,但如果确实如此,那么就没有
    int
    delete

  2. 可能将参数移动构造为

    foo
    (除非已经从
    std::make_unique
    进行了RVO)。如果发生的话,那就
    noexcept

  3. 调用

    foo
    ——但
    foo
    不会在结束时破坏它自己的参数
    }

  4. 可能会破坏临时文件(如果有)——但它显然处于移出 (

    nullptr
    ) 状态。

FWIW,使

foo()
成为
noexcept
会稍微减少代码生成 - 但仍然存在潜在的
delete

https://godbolt.org/z/8hEhG5Weq

c++ unique-ptr code-size
1个回答
0
投票

使用

make_unique
的调用正在创建一个临时对象。 当该临时对象超出范围时,将调用其析构函数。 您知道,当复制参数时,该临时变量将处于指针为空的状态,并且析构函数将无事可做 - 但编译器不知道这一点。 因此,无论如何它都必须调用析构函数,并且该调用将成为代码的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.