グローバル関数を強制的にインライン化するために MS 固有のキーワードを使用していますが、明示的な単純なデストラクタを持つオブジェクトを使用すると、関数がインライン化に失敗することに気付きました。
MSDNからの引用
を使用しても
__forceinline
、コンパイラはすべての状況でコードをインライン化できるわけではありません。次の場合、コンパイラは関数をインライン化できません。
関数またはその呼び出し元は
/Ob0
(デバッグ ビルドの既定のオプション) でコンパイルされます。関数と呼び出し元は、異なるタイプの例外処理を使用します (一方は C++ 例外処理、もう一方は構造化例外処理)。
関数には可変引数リストがあります。
/Og
関数は、 、/Ox
、/O1
、またはでコンパイルされていない限り、インライン アセンブリを使用します/O2
。この関数は再帰的で、 を伴いません
#pragma inline_recursion(on)
。プラグマを使用すると、再帰関数はデフォルトの深さ 16 呼び出しにインライン化されます。インライン化の深さを減らすには、inline_depth
pragma を使用します。関数は仮想であり、仮想的に呼び出されます。仮想関数への直接呼び出しはインライン化できます。
プログラムは関数のアドレスを取得し、呼び出しは関数へのポインターを介して行われます。アドレスが取得された関数への直接呼び出しは、インライン化できます。
この関数は、naked
__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 時間以内に更新します