本文介绍了const引用临时生命期延长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于一些C ++标准合规性或缺乏的问题。

I have a question about some C++ standard compliance or lack of it.

在我的项目中,我使用一些简单的Guard类,它使用const引用技巧。我使用Visual Studio 2005和有两种配置 - 一个用于正常版本构建和第二个单元测试。

In my project I'm using some simple Guard class that uses the const reference trick. I'm using Visual Studio 2005 and there are two configurations - one for normal release build and the second one for unit tests.

在这两种情况下,有一些临时挂const引用到底,但是在此期间发生的是什么问题。对于发布配置,const引用直接指向创建Guard实例的辅助函数模板的返回中创建的temp(没有调用任何拷贝构造函数,甚至没有实例化)。

In both cases there is some temporary hanging on the const reference in the end, but what happens in the meantime is the problem. For release configuration, the const reference points directly to the temp created in the return of the helper function template that creates the Guard instance ( no copy constructor is called, not even instantiated for that matter ).

但是对于单元测试conf,函数模板temp首先被复制,然后它的析构函数被调用,只有在const引用超出范围之后才能做。

But for unit test conf the function template temp is first copied and then its destructor is called, doing what should be done only after the const reference goes out of scope.

我已经解决了这个问题,通过禁用基类复制构造函数中的原始守卫(所以析构函数中的动作不会触发配置为其复制构造函数),但是困扰我是:

I have solved the problem by disabling the original guard in base class copy constructor ( so the action in destructor is not triggered for config for which copy constructor is called ), but what bothers me is:

复制临时行为是否符合标准?标准是告诉const引用应该直接指向temp,还是这个实现定义的行为没有在标准中指定?

Is the copy-the-temporary behaviour standard-compliant? Does the standard tells that the const reference should point directly to the temp, or is this implementation-defined behaviour not specified in the standard?

我的代码基本上是

从DDJ和Herb Sutter的getw 88文章中的范围守卫文章,但这两个来源似乎没有考虑更早的析构函数调用。

Any info from someone more knowledgeable will be appreciated.

编辑:

确定代码如下:

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;


推荐答案


如果你有这样的代码:

Both behaviours are standards conforming.If you have code like this:

T foo()
{
  return T();
}

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

然后,在概念上,在 foo ,创建一个临时对象。这个临时文件被复制到 foo 的返回值。在 main 中,此副本(也是一个临时对象)绑定到 x

作为 foo 的返回值的副本获得其生命周期延长,而不是作为副本源的临时副本。

Then, conceptually, in foo, a temporary object is created. This temporary is copied to the return-value of foo. In main, this copy (which is also a temporary object) is bound to x.
The copy that is the return-value from foo gets its lifetime extended, but not the temporary that was the source for the copy.

但是,C ++标准明确允许消除冗余临时对象。因此, foo 可以直接在该槽中创建临时文件,而不是创建临时文件并将其复制到插槽中以返回值。

这两个选项

But, the C++ standard explicitly allows redundant temporary objects to be elided. So instead of creating a temporary and copying that over into the slot for return values, foo can directly create the temporary in that slot.
Both options are possible, and the compiler does not even have to document when it uses which option.

C ++标准的相关章节是6.6.3([stmt.return])和12.2([class.temporary])。

The relevant sections of the C++ standard are 6.6.3 ([stmt.return]) and 12.2 ([class.temporary]).

这篇关于const引用临时生命期延长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-16 08:29