为什么我的模板函数不能内联
Why can't my template function be inlined
我写了一个 class 可以在其中存储 lambda 函数,以确保在函数退出之前释放所有资源。
我在 MSVC2015
、Release
模式下测试我的代码 /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)
{
}
我写了一个 class 可以在其中存储 lambda 函数,以确保在函数退出之前释放所有资源。
我在 MSVC2015
、Release
模式下测试我的代码 /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)
{
}