3

我对某些 C++ 标准合规性或缺乏它有疑问。

在我的项目中,我使用了一些使用 const 引用技巧的简单 Guard 类。我正在使用 Visual Studio 2005,有两种配置 - 一种用于正常发布版本,另一种用于单元测试。

在这两种情况下,最后都会在 const 引用上临时挂起,但同时发生的事情就是问题所在。对于发布配置, const 引用直接指向在创建 Guard 实例的辅助函数模板的返回中创建的 temp(没有调用复制构造函数,甚至没有实例化)。

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

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

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

我的代码大致基于 DDJ 中的 Scope Guard 文章和 Herb Sutter 的 gotw 88 文章,但是这两个来源似乎都没有考虑到早期的析构函数调用。

来自知识渊博的人的任何信息将不胜感激。

编辑:

好的,代码是这样的:

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;
4

1 回答 1

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])。

于 2010-11-03T11:48:20.117 回答