2010-11-03 9 views
3

У меня есть вопрос о соблюдении стандартного стандарта C++ или его отсутствии.константа для временного удлинения срока службы

В моем проекте я использую простой класс Guard, который использует трюк const const. Я использую Visual Studio 2005 и есть две конфигурации - одна для обычной сборки релиза, а вторая для модульных тестов.

В обоих случаях в конце есть некоторое временное зависание ссылки на const, но то, что происходит в это время, является проблемой. Для конфигурации релиза ссылка const ссылается непосредственно на temp, созданный при возврате шаблона вспомогательной функции, который создает экземпляр Guard (никакой конструктор копирования не вызывается, даже не созданный для этого).

Но для тестирования устройства conf шаблон функции temp сначала копируется, а затем вызывается его деструктор, делая то, что должно быть сделано только после того, как ссылка на const перестает быть видимой.

Я решил эту проблему путем отключения оригинального охранника в базовой копии класса конструктора (так что действие в деструктор не вызывается для конфигурации, для которых конструктор копирования называется), но то, что беспокоит меня:

ли совместимость с копией по времени стандартная? Указывает ли стандарт, что ссылка const должна указывать непосредственно на temp, или это поведение, определяемое реализацией, не указано в стандарте?

Я основываю свой код примерно на предметной статье Scope Guard в статье DDJ и Herb Sutter's 88, но оба этих источника, похоже, не учитывают более ранний вызов деструктора.

Любая информация от кого-то более знающего будет оценена по достоинству.

EDIT:

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; 
+1

Есть код для иллюстрации? – sharptooth

+0

Без кода невозможно точно сказать. Все ответы будут догадками. –

ответ

4

Оба поведения являются стандарты, соответствующие. Если у вас есть такой код:

T foo() 
{ 
    return T(); 
} 

int main() 
{ 
    const T& x = foo(); 
} 

Затем, концептуально, в foo, временный объект создается. Это временное значение копируется в возвращаемое значение foo. В main эта копия (которая также является временным объектом) привязана к x.
Копия, которая является возвращаемым значением от foo, получает продление срока службы, но не временную, которая была источником для копии.

Но, стандарт C++ явно позволяет исключить избыточные временные объекты. Поэтому вместо создания временного копирования и копирования в слот для возвращаемых значений foo может непосредственно создать временное место в этом слоте.
Возможны оба варианта, и компилятор даже не должен документировать, когда он использует какой параметр.

Соответствующие разделы стандарта C++: 6.6.3 ([stmt.return]) и 12.2 ([class.temporary]).

+1

Хорошо, я снова снял статью ScopeGuard и действительно использовал то же самое решение, что и я, - отключив другого защитника в конструкторе копирования базового класса.Я, должно быть, пропустил эту часть :). Но, тем не менее, статья Саттера нигде не указывает на возможность вызова деструктора дважды. Большое спасибо за claryfing это. – altariste

 Смежные вопросы

  • Нет связанных вопросов^_^