【发布时间】:2014-11-05 21:47:44
【问题描述】:
我正在使用特定于 MS 的关键字来强制内联全局函数,但我注意到如果该函数使用具有显式平凡析构函数的对象,则该函数无法内联自身。
引用MSDN
即使使用
__forceinline,编译器也不能完全内联代码 情况。如果出现以下情况,编译器不能内联函数:
函数或其调用者使用
/Ob0(调试构建的默认选项)编译。函数和调用者使用不同类型的异常处理(C++异常处理合二为一,结构化异常处理 在另一个)。
函数有一个变量参数列表。
该函数使用内联汇编,除非使用
/Og、/Ox、/O1或/O2编译。函数是递归的,不伴随
#pragma inline_recursion(on)。使用 pragma,递归函数被内联到 16 个调用的默认深度。要减少内联深度,请使用inline_depthpragma。函数是虚拟的,被虚拟调用。可以内联对虚拟函数的直接调用。
程序获取函数的地址,并通过指向函数的指针进行调用。可以内联对已获取地址的函数的直接调用。
该函数还标有裸
__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 小时内更新
【问题讨论】:
-
询问编写编译器的人,并可能提交错误报告。
-
@n.m.:我会,但在此之前我想问问社区,他们是否知道这个问题,或者我是否遗漏了一些明显的东西 :-)
-
是否缺少
#define?INLINE __forceinline -
Spam的析构函数根据 C++ 标准中“平凡”的定义,并不是平凡的。在VS2013中,你可以试试~Spam() = default;,如果数据成员的dtor是微不足道的,这将是微不足道的。
标签: c++ visual-c++ inlining