У меня есть вопрос о соответствии стандарту C ++ или его отсутствии.
В моем проекте я использую некоторый простой класс Guard, который использует трюк с константой. Я использую Visual Studio 2005 и есть две конфигурации - одна для обычной сборки релиза и вторая для модульных тестов.
В обоих случаях происходит временное зависание константной ссылки в конце, но проблема заключается в том, что происходит. Для конфигурации релиза константная ссылка указывает непосредственно на временную переменную, созданную в возвращении шаблона вспомогательной функции, который создает экземпляр Guard (конструктор копирования не вызывается, даже не создается).
Но для conf модульного теста сначала копируется шаблон функции temp, а затем вызывается его деструктор, что делает то, что должно быть сделано только после того, как ссылка на const выходит из области видимости.
Я решил проблему, отключив исходную защиту в конструкторе копирования базового класса (поэтому действие в деструкторе не запускается для конфигурации, для которой вызывается конструктор копирования), но меня беспокоит следующее:
Соответствует ли поведение при временном копировании стандарту? Стандарт говорит, что ссылка на const должна указывать непосредственно на temp, или это поведение, определяемое реализацией, не указано в стандарте?
Мой код основан примерно на статье Scope Guard в DDJ и статье Герба Саттера 88, но оба эти источника, похоже, не принимают во внимание более ранний вызов деструктора.
Любая информация от кого-то более знающего будет оценена.
EDIT:
Хорошо, код выглядит примерно так:
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;