以下のように、C++ 11でラムダを使用してfinallyシミュレーターを作成しました。
#include <cstdio>
template<typename Functor>
struct Finalizer
{
Finalizer(Functor& func) : func_(func) {} // (1)
~Finalizer() { func_(); }
private:
Functor func_; // (2)
};
template<typename functor>
Finalizer<functor> finally(functor& func)
{
return Finalizer<functor>(func); (3)
}
int main()
{
int a = 20;
// print the value of a at the escape of the scope
auto finalizer = finally([&]{ printf("%d\n", a); }); // (4)
}
コードは意図したとおりに動作しますが、 Finalizer構造体 (1)の ctor で望ましくない (ラムダ ファンクターの) copy ctor 呼び出しがあります。(ありがたいことに、 finally関数 (3 -> 4)の return ステートメントでのコピー構築は、RVO によって回避されます。)
コンパイラはコピー ctor 呼び出しを排除しません (少なくとも vc10 では - gcc はそれを最適化する可能性があります)。Finalizer struct (2) のファンクターの型が参照に変更されると、 finally呼び出しでのラムダ引数( 4) は r 値です。
もちろん、コードは以下のように「最適化」できます
template<typename Functor>
struct Finalizer
{
Finalizer(Functor& func) : func_(func) {}
~Finalizer() { func_(); }
private:
Functor& func_;
};
int main()
{
int a = 20;
auto finalizer = [&]{ printf("%d\n", a); };
Finalizer<decltype(finalizer)> fin(finalizer);
}
オーバーヘッドはなく、printf呼び出しのみがスコープの最後に配置されます。でも… 好きじゃない。:(マクロでラップしようとしましたが、2つの「名前」を宣言する必要があります-1つはラムダオブジェクト用、もう1つはファイナライザーオブジェクト用です。
私の目的は単純です -
- 回避できる不要なパフォーマンスのオーバーヘッドはすべて排除する必要があります。理想的には、関数呼び出しがなく、すべてのプロシージャがインライン化されている必要があります。
- 効用関数の目的として簡潔な式を維持します。マクロの使用は許可されていますが、お勧めできません。
この状況でそれを回避する解決策はありますか?