постоянная ссылка для временного продления жизни - PullRequest
3 голосов
/ 03 ноября 2010

У меня есть вопрос о соответствии стандарту 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;

1 Ответ

4 голосов
/ 03 ноября 2010

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

T foo()
{
  return T();
}

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

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

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

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

...