C++標準への準拠またはその欠如について質問があります。
私のプロジェクトでは、const参照トリックを使用するいくつかの単純なGuardクラスを使用しています。Visual Studio 2005を使用していますが、2つの構成があります。1つは通常のリリースビルド用で、もう1つは単体テスト用です。
どちらの場合も、最終的にconst参照に一時的にぶら下がっていますが、その間に何が起こるかが問題です。リリース構成の場合、const参照は、Guardインスタンスを作成するヘルパー関数テンプレートの戻りで作成された一時を直接指します(コピーコンストラクターは呼び出されず、そのことについてはインスタンス化されません)。
ただし、単体テストconfの場合、関数テンプレートtempが最初にコピーされ、次にそのデストラクタが呼び出され、const参照がスコープ外になった後にのみ実行する必要があります。
基本クラスのコピーコンストラクターで元のガードを無効にすることで問題を解決しました(したがって、コピーコンストラクターが呼び出される構成に対してデストラクタのアクションはトリガーされません)が、気になるのは次のとおりです。
一時的なコピーの動作は標準に準拠していますか?標準は、const参照が直接tempを指す必要があることを示していますか、それともこの実装定義の動作は標準で指定されていませんか?
私はコードをDDJのScopeGuardの記事とHerbSutterのgotw88の記事に大まかに基づいていますが、これらのソースはどちらも以前のデストラクタ呼び出しを考慮していないようです。
より知識のある人からの情報をいただければ幸いです。
編集:
コードは次のようなものです。
class GuardBase
{
public:
GuardBase() : m_enabled(true)
{}
//this is done because in normal build no copy constructor is called ( directly using the function temporary)
//but for UT conf somehow the original temp is copied and destroyed
GuardBase(const GuardBase& other)
{
other.disable();
}
void disable() const
{
m_enabled = false;
}
protected:
//member is mutable because we will access the object through the const reference
mutable bool m_enabled;
};
template< typename Arg, typename ObjType, typename MemberMethod >
class Guard1Arg : public GuardBase
{
public:
Guard1Arg(ObjType& obj, MemberMethod remover, Arg arg) : m_arg(arg), m_remover(remover), m_object(obj)
{}
~Guard1Arg()
{
if ( m_enabled )
{
(m_object.*m_remover)(m_arg);
}
}
private:
Arg m_arg;
MemberMethod m_remover;
ObjType& m_object;
//this class should not be assigned
Guard1Arg& operator=(const Guard1Arg& other);
};
//utility template function used to create Guards using member functions with 1 argument
template<typename MemberFunction, typename Obj, typename Arg>
Guard1Arg<Arg, Obj, MemberFunction> MakeGuard1Arg(Obj& obj, MemberFunction memberFunction, Arg& arg)
{
return Guard1Arg<Arg, Obj, MemberFunction>(obj, memberFunction, arg);
}
#define GUARD_CREATE(arg, remover) const GuardBase& guard = MakeGuard1Arg(*this, remover, arg);
#define GUARD_DISABLE guard.disable();
#define GUARD_FRIEND template< typename Arg, typename ObjType, typename MemberMethod > friend class Guard1Arg;