我正在使用特定于 MS 的关键字来强制内联全局函数,但我注意到如果该函数使用具有显式平凡析构函数的对象,则该函数无法内联自身。
引用MSDN
即使使用
__forceinline
,编译器也不能在所有情况下内联代码。如果出现以下情况,编译器不能内联函数:
该函数或其调用者是用
/Ob0
(调试构建的默认选项)编译的。函数和调用者使用不同类型的异常处理(一种是 C++ 异常处理,另一种是结构化异常处理)。
该函数有一个可变参数列表。
该函数使用内联汇编,除非使用
/Og
、/Ox
、/O1
或编译/O2
。该函数是递归的,不伴随
#pragma inline_recursion(on)
. 使用 pragma,递归函数被内联到 16 个调用的默认深度。要减少内联深度,请使用inline_depth
pragma。该函数是虚拟的,并且被虚拟调用。可以内联对虚拟函数的直接调用。
程序获取函数的地址,并通过指向函数的指针进行调用。可以内联对已获取地址的函数的直接调用。
该函数还标有裸
__declspec
修饰符。
我正在尝试以下自包含程序来测试行为
#include <iostream>
#define INLINE __forceinline
template <class T>
struct rvalue
{
T& r_;
explicit INLINE rvalue(T& r) : r_(r) {}
};
template <class T>
INLINE
T movz(T& t)
{
return T(rvalue<T>(t));
}
template <class T>
class Spam
{
public:
INLINE operator rvalue<Spam>() { return rvalue<Spam>(*this); }
INLINE Spam() : m_value(0) {}
INLINE Spam(rvalue<Spam> p) : m_value(p.r_.m_value) {}
INLINE Spam& operator= (rvalue<Spam> p)
{
m_value = p.r_.m_value;
return *this;
}
INLINE explicit Spam(T value) : m_value(value) { }
INLINE operator T() { return m_value; };
template <class U, class E> INLINE Spam& operator= (Spam<U> u) { return *this; }
INLINE ~Spam() {}
private:
Spam(Spam<T>&); // not defined
Spam& operator= (Spam&); // not defined
private:
T m_value;
};
INLINE int foo()
{
Spam<int> p1(int(5)), p2;
p2 = movz(p1);
return p2;
}
int main()
{
std::cout << foo() << std::endl;
}
有了简单的析构函数INLINE ~Spam() {}
,我们有以下反汇编
int main()
{
000000013F4B1010 sub rsp,28h
std::cout << foo() << std::endl;
000000013F4B1014 lea rdx,[rsp+30h]
000000013F4B1019 lea rcx,[rsp+38h]
000000013F4B101E mov dword ptr [rsp+30h],5
000000013F4B1026 call movz<Spam<int> > (013F4B1000h)
000000013F4B102B mov rcx,qword ptr [__imp_std::cout (013F4B2050h)]
000000013F4B1032 mov edx,dword ptr [rax]
000000013F4B1034 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (013F4B2040h)]
000000013F4B103A mov rdx,qword ptr [__imp_std::endl (013F4B2048h)]
000000013F4B1041 mov rcx,rax
000000013F4B1044 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (013F4B2058h)]
}
在没有析构函数的情况下,INLINE ~Spam() {}
我们有以下反汇编
int main()
{
000000013FF01000 sub rsp,28h
std::cout << foo() << std::endl;
000000013FF01004 mov rcx,qword ptr [__imp_std::cout (013FF02050h)]
000000013FF0100B mov edx,5
000000013FF01010 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (013FF02040h)]
000000013FF01016 mov rdx,qword ptr [__imp_std::endl (013FF02048h)]
000000013FF0101D mov rcx,rax
000000013FF01020 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (013FF02058h)]
}
000000013FF01026 xor eax,eax
}
我无法理解,为什么在存在析构函数的情况下,编译器无法内联函数T movz(T& t)
- 注意行为从 2008 年到 2013 年是一致的
- 注意我检查了 cygwin-gcc 但编译器确实内联了代码。我目前无法验证其他编译器,但如果需要,我会在接下来的 12 小时内更新