为什么我的模板函数不能内联

Why can't my template function be inlined

我写了一个 class 可以在其中存储 lambda 函数,以确保在函数退出之前释放所有资源。

我在 MSVC2015Release 模式下测试我的代码 /O2

但是我发现GenerateScopeGuard不能内联,生成了一个小函数

int main()
{
01031C00 55                   push        ebp  
01031C01 8B EC                mov         ebp,esp  
01031C03 51                   push        ecx  
    auto func = GenerateScopeGuard([] {printf("hello\n"); });
01031C04 8D 4D FC             lea         ecx,[func]  
01031C07 E8 24 00 00 00       call        GenerateScopeGuard<<lambda_8b2f3596146f3fc3f8311b4d76487aed> > (01031C30h)  
    return 0;
01031C0C 80 7D FD 00          cmp         byte ptr [ebp-3],0  
01031C10 75 0D                jne         main+1Fh (01031C1Fh)  
01031C12 68 78 61 03 01       push        offset string "hello\n" (01036178h)  
01031C17 E8 24 00 00 00       call        printf (01031C40h)  
01031C1C 83 C4 04             add         esp,4  
01031C1F 33 C0                xor         eax,eax  
}
01031C21 8B E5                mov         esp,ebp  
01031C23 5D                   pop         ebp  
01031C24 C3                   ret  

    return ScopeGuard<T>(std::forward<T>(func));
01031C30 C6 41 01 00          mov         byte ptr [ecx+1],0  
01031C34 8B C1                mov         eax,ecx  
}
01031C36 C3                   ret  

看起来与异常处理有关。事实上,如果我禁用 C++ 异常,该函数是内联的,但不适用于 /EHsc。为什么?

这是我的代码。

template<typename T>
class ScopeGuard
{
public:
    ScopeGuard(const ScopeGuard&) = delete;
    ScopeGuard& operator=(const ScopeGuard&) = delete;

    explicit ScopeGuard(T&& func) :
        func_(std::forward<T>(func))
    {}

    ScopeGuard(ScopeGuard&& right) :
        func_(std::move(right.func_))
    {}

    ~ScopeGuard()
    {
        if (!dismissed_) func_();
    }

    void Dismiss()
    {
        dismissed_ = true;
    }

private:
    T func_;
    bool dismissed_ = false;
};

template<typename T>
__forceinline ScopeGuard<T> GenerateScopeGuard(T&& func) noexcept
{
    return ScopeGuard<T>(std::forward<T>(func));
}

int main()
{
    auto func = GenerateScopeGuard([] {printf("hello\n"); });
    return 0;
}

使用 -O3 -std=c++14 编译:

gcc 5.4 的输出:

.LC0:
        .string "hello"
main:
        subq    , %rsp
        movl    $.LC0, %edi
        call    puts
        xorl    %eax, %eax
        addq    , %rsp
        ret

clang 3.8 的输出:

main:                                   # @main
        pushq   %rax
        movl    $.Lstr, %edi
        callq   puts
        xorl    %eax, %eax
        popq    %rcx
        retq

.Lstr:
        .asciz  "hello"

这没有非标准 __forceinline 属性。

您确定已启用优化吗?

难道这个函数是生成的,不是main调用的?

最近引入的非静态成员初始化功能似乎让 MSVC 编译器感到困惑。带初始化的构造函数似乎解决了这个问题:

ScopeGuard()
    : dismissed_(false)
{
}