Question

J'ai une question sur une certaine conformité C ++ standard ou absence.

Dans mon projet, j'utilise une classe simple garde qui utilise l'astuce de référence const. J'utilise Visual Studio 2005 et il y a deux configurations -. Pour une version release normale et la seconde pour les tests unitaires

Dans les deux cas, il y a une suspension temporaire sur la référence const à la fin, mais ce qui se passe dans l'intervalle est le problème. Pour la configuration de sortie, les points de référence const directement à la température créée dans le retour du modèle de fonction d'aide qui crée l'instance Guard (pas constructeur de copie est appelé, même pas instancié pour cette question).

Mais pour test unitaire de la température conf modèle de fonction est d'abord copié puis son destructor est appelé, faire ce qui doit être fait qu'après la référence const est hors de portée.

J'ai résolu le problème en désactivant la garde d'origine dans le constructeur de copie de classe de base (donc l'action destructor ne se déclenche pas pour config pour laquelle constructeur de copie est appelé), mais ce qui me dérange est:

La copie le temporaire conforme aux normes de comportement? La norme indique que la référence const doit pointer directement à la température, ou est-ce comportement de mise en œuvre défini non spécifié dans la norme?

Je base mon code à peu près sur l'article de la Garde Scope GotW 88 article DDJ et Herb Sutter, mais les deux que ces sources ne semblent pas prendre l'appel destructor plus tôt en compte.

Toute information de quelqu'un de plus compétent sera apprécié.

EDIT:

Ok le code est quelque chose comme ceci:

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;
Était-ce utile?

La solution

Les deux comportements sont conformes aux normes. Si vous avez du code comme ceci:

T foo()
{
  return T();
}

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

Ensuite, sur le plan conceptuel, en foo, un objet temporaire est créé. est recopié Ce temporaire au retour de la valeur foo. En main, cette copie (qui est aussi un objet temporaire) est lié à x.
La copie qui est la valeur de retour de foo obtient sa durée de vie prolongée, mais pas temporaire qui a été la source de la copie.

Mais, le C ++ standard permet explicitement des objets temporaires redondants à élidés. Ainsi, au lieu de créer une copie temporaire et que plus dans la fente pour les valeurs de retour, foo peut créer directement temporaire dans ce créneau.
Les deux options sont possibles, et le compilateur n'a même pas le document lorsqu'il utilise l'option.

Les sections pertinentes de la norme C ++ sont 6.6.3 ([stmt.return]) et 12.2 ([class.temporary]).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top