一時的な生涯延長のためのconst参照
-
28-09-2019 - |
質問
C ++標準コンプライアンスまたはそれの欠如について質問があります。
私のプロジェクトでは、Const Reference Trickを使用するいくつかの単純なガードクラスを使用しています。 Visual Studio 2005を使用していますが、2つの構成があります。1つは通常のリリースビルド用で、もう1つはユニットテスト用です。
どちらの場合も、最終的にはconst参照に一時的なぶら下がっていますが、その間に起こることは問題です。リリース構成の場合、constの参照は、ガードインスタンスを作成するヘルパー関数テンプレートの返された状態で作成された温度を直接ポイントします(コピーコンストラクターは呼び出されず、その点ではインスタンス化されません)。
ただし、ユニットテストConfの場合、関数テンプレートTEMPが最初にコピーされ、次にそのデストラクタが呼び出され、const参照が範囲外になった後にのみ行うべきことを行います。
私は、基本クラスのコピーコンストラクターで元のガードを無効にすることで問題を解決しました(したがって、デストラクタのアクションは、コピーコンストラクターが呼び出される構成に対してトリガーされません)が、私が気になるのは次のとおりです。
共同体の行動は標準的なものですか?標準は、const参照が温度を直接指すべきであるか、またはこの実装定義の動作は標準で指定されていないことを示していますか?
私はコードをDDJとHerb SutterのGoTW 88の記事のScope Guardの記事におおまかに基づいていますが、これらの情報源は両方とも以前のDestructor Callを考慮していないようです。
より知識のある人からの情報は大歓迎です。
編集:
OKコードは次のようなものです:
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;
解決
どちらの動作も標準に準拠しています。このようなコードがある場合:
T foo()
{
return T();
}
int main()
{
const T& x = foo();
}
その後、概念的には、 foo
, 、一時的なオブジェクトが作成されます。この一時的なものは、return-valueにコピーされます foo
. 。の main
, 、このコピー(一時的なオブジェクトでもあります)は x
.
return-valueからのコピー foo
生涯延長されますが、コピーのソースであった一時的なものではありません。
ただし、C ++標準により、冗長な一時的なオブジェクトを明示的に排除できます。したがって、一時的なものを作成し、それを返す値のためにスロットにコピーする代わりに、 foo
そのスロットに一時を直接作成できます。
どちらのオプションも可能であり、コンパイラはどのオプションを使用しても文書化する必要さえありません。
C ++標準の関連セクションは、6.6.3([stmt.return])および12.2([class.temporary])です。