3

J'ai une implémentation de pointeur automatique:constructeur pointeur automatique en VC2008

template <typename T, bool Arr = false> 
class GAutoPtr 
{ 
    T *Ptr; 

public: 
    typedef GAutoPtr<T, Arr> &AutoPtrRef; 

    GAutoPtr(T *ptr = 0) 
    { 
     Ptr = ptr; 
    } 

    GAutoPtr(AutoPtrRef p) 
    { 
     Ptr = p.Release(); 
    } 

    ~GAutoPtr() { Empty(); } 
    operator T*() { return Ptr; } 
    T *Get() { return Ptr; } 
    T *operator->() const { LgiAssert(Ptr); return Ptr; } 

    inline void Empty() 
    { 
     if (Arr) 
      delete [] Ptr; 
     else 
      delete Ptr; 
     Ptr = 0; 
    } 

    AutoPtrRef operator =(GAutoPtr<T> p) 
    { 
     Empty(); 
     Ptr = p.Ptr; 
     p.Ptr = 0; 
     return *this; 
    } 

    void Reset(T *p) 
    { 
     if (p != Ptr) 
     { 
      Empty(); 
      Ptr = p; 
     } 
    } 

    T *Release() 
    { 
     T *p = Ptr; 
     Ptr = 0; 
     return p; 
    } 
}; 

typedef GAutoPtr<char, true> GAutoString; 
typedef GAutoPtr<char16, true> GAutoWString; 

Et cela fonctionne très bien dans Visual C++ 6. Toutefois, dans Visual C++ 2005 ou 2008, je ne peux pas retourner un pointeur automatique d'une fonction sans les choses vont horriblement mal.

par exemple.

GAutoString Func() 
{ 
    char *s = new char[4]; 
    strcpy(s, "asd"); 
    return s; 
} 

int main() 
{ 
    GAutoString a = Func(); 
    /// a.Ptr is now garbage 
} 

Qu'est-ce qui se passe est que le compilateur crée un GAutoString temporaire pour maintenir la valeur de retour de la fonction, puis en passant que la variable « a » sur la pile Calles l'opérateur T *() de la température variable, puis le constructeur GAutoPtr (T * ptr = 0), au lieu de simplement utiliser le constructeur de copie: GAutoPtr (AutoPtrRef p)

Il en résulte le temp auto ptr la suppression de la mémoire et «un» tenant un pointeur sur la mémoire libérée.

Cependant, dans VC6, il appelle le bon constructeur. Maintenant, en disant tout cela, j'utilise aussi gcc sur Linux et Mac, donc tout code que j'écris doit fonctionner là aussi. VC2008 vous empêche d'utiliser une variable non-const par valeur dans le constructeur de copie. De plus, je ne veux pas de "const", car le constructeur de copie prend possession du bloc de mémoire qui supprime la propriété de l'objet en cours de copie ... le modifiant ainsi.

Comment puis-je faire cela fonctionner dans VC 2005/2008?

Répondre

1

Est-ce que cela compile même sous un g ++ récent? Je l'ai essayé sur mon MacBook Pro et:

xxx.cpp: In function ‘AutoString func()’: 
xxx.cpp:52: error: no matching function for call to ‘AutoPtr<char, true>::AutoPtr(AutoString)’ 
xxx.cpp:12: note: candidates are: AutoPtr<T, isArray>::AutoPtr(AutoPtr<T, isArray>&) [with T = char, bool isArray = true] 
xxx.cpp:9: note:     AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true] 
xxx.cpp:52: error: initializing temporary from result of ‘AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]’ 

La seule façon que je peux obtenir ce pour compiler est en faisant le constructeur de copie prendre une référence const qui est ce que je soupçonnais. Il ressemble à Herb Sutter posted about something very similar à cela dans son GotW le plus récent. Je ne voudrais pas essayer de reproduire la sémantique de transfert de propriété de std::auto_ptr sans une très bonne raison. Vous pourriez vouloir regarder les différents goodies dans Boost.SmartPtr. Si possible, utilisez-les à la place.

Si vous ne pouvez pas Boost pour une raison quelconque, alors lisez votre implémentation préférée std::auto_ptr et accordez une attention particulière à la classe std::auto_ptr_ref. Une fois que vous comprenez pourquoi il est là et exactement comment il le fait, alors revenez en arrière et écrivez une classe auto-ptr. Cette classe existe pour contourner le problème que vous voyez. IIRC, ceci est discuté en détail dans Josuttis': The Standard C++ Library. Je pense que c'est là que je l'ai vraiment compris pour la première fois.

+0

Fini par avoir besoin de plus que le mot clé 'explicite', j'ai donc distillé une solution de STL en utilisant la classe auto_ptr_ref. Jusqu'ici tout va bien. – fret

1

Vous pouvez marquer le constructeur qui prend l'argument T * avec le mot clé "explicit". J'ai vérifié que cela fonctionne et empêche également la création de l'objet temporaire parasite, une amélioration des performances. Cependant, toute personne utilisant ce constructeur ne peut plus se fier aux règles de conversion du type de compilateur. Par exemple, vous fonctionnez changerait à ceci:

GAutoString Func() 
{ 
    char *s = new char[4]; 
    strcpy(s, "asd"); 
    return GAutoString(s); 
} 

Il est ennuyeux, mais je ne pense pas que ce soit nécessairement une mauvaise chose dans ce cas que les conversions de type automatique peuvent être source de confusion.

+0

Oui, ça marche. Je dois nettoyer une nouvelle conversion automatique comme vous l'avez dit ... mais je préfère que les applications le crash;) – fret