Bienvenue sur le forum !

Si vous souhaitez rejoindre la communauté, cliquez sur l'un de ces boutons !

Qt 5 : 5.9.1 - Qt Creator : 4.4.0 - Qt Installer : 2.0.3 - JOM : 1.1.2 - Qt Build suite : 1.7.0 - VS Qt 5 : 2.0.0

Appeler un destructeur sur une valeur T dans une fonction template

Bonjour !

J'ai créé une classe template qui stocke des valeurs de type T dans un tableau m_data :
m_data = new T [nbre d'éléments]
Ce type T est vraiment quelconque, donc peut être un pointeur.
J'ai parfois besoin de redimensionner m_data. Je peux faire un delete puis un new, mais avant le delete je souhaite appeler le destructeur de chaque élément T stocké.

Comment fait-on ??

Merci !

Réponses

  • 27 Feb modifié
    Salut,

    Pour ton cas, je ne vois pas trop de solutions élégantes.
    Celle qui me vient à l'esprit serait de spécialiser ta classe template avec T*
    de ce fait ça fait écrire 2 constructeur. Ensuite ton tableau dynamique devient T** m_data.
    En attendant l'avis d'un bigboss tel que @gbdivers, je poste un exemple

    En gros :

    #ifndef MYTEMPLATECLASS_H
    #define MYTEMPLATECLASS_H

    template<class X> class TestBase
    {

    public:
    void reallocate(int size) {
    deleteT();
    allocate(size);
    }
    virtual ~TestBase() {
    deleteT();
    }

    protected:
    void allocate(int size) {
    m_size = size;
    p_tab = new X*[m_size];
    for (int i = 0; i < m_size; i++) {
    p_tab[i] = new X;
    }
    }

    void deleteT() {
    for (int i = 0; i < m_size; i++) {
    delete p_tab[i];
    }
    delete [] p_tab;
    }

    protected:
    X** p_tab;
    int m_size;
    };

    template <typename T>
    class MyTemplateClass : public TestBase<T>
    {
    public:

    MyTemplateClass<T>::MyTemplateClass(int size = 5)
    {
    allocate(size);
    }
    };

    template<typename T>
    class MyTemplateClass<T*> : public TestBase<T>
    {
    public:
    MyTemplateClass<T*>::MyTemplateClass(int size = 5)
    {
    allocate(size);
    }
    };

    #endif
    Utilisation :

    //alloue 2 instances de TestClass
    MyTemplateClass<TestClass*> A(2);
    //ici aussi
    MyTemplateClass<TestClass> B(2);
    //ici on delete tout et on réalloue
    A.reallocate(3);
    B.reallocate(3);

    Dites moi si c'est moche :D
  • Pas besoin de faire une classe de base, tu peux directement spécialiser la base.
  • @gbdivers : c'est vrai ;)
  • Au risque de dire une bêtise, le destructeur n'est il pas appelé automatiquement lors d'un delete (ou quand on sors du scope de l'objet) ? Il me semble que c'est une des caractéristiques du C++.
  • 27 Feb modifié
    Si pour l'objet que tu delete (le tableau ici). Mais pas pour les objets pointés.
    Object* p = new Object[5]; // tableau de 5 objets
    delete p; // les destructeurs de 5 objets sont appelés.

    Object** p = new Object*[5]; // tableau de 5 pointeurs sur objets
    for (size_t i=0; i<5; ++i)
    p[i] = new Object;
    delete[] p; // le destructeur du tableau est appelé, pas les destructeurs des 5 objets
  • 27 Feb modifié
     char* p = new[5] char; 
    J'ai une erreur :
     error: expected a type
    char* p=new[5] char;
    ^
    D'autre part pour les tableaux, j'ai l'habitude de faire: delete[]
    C'est quoi cette syntaxe ? C++ 14 ?
  • D'autre part pour les tableaux, j'ai l'habitude de faire: delete[]
    Erreur de ma part, j'ai corrigé.
    J'ai une erreur :
    Mouais, ok, j'ai encore fait une erreur, je corrige.

    (HS : je t'aime pas)
  • Merci à tous !

    Ma classe reçoit des valeurs T, elle ne les crée pas. Je suis étonné que personne ne m'ait objecté que c'est celui qui fait new qui doit faire delete. ;)
  • Bonjour,

    On peut appeler directement le destructeur de chaque objet contenu dans un vecteur dans le genre :

    template < typename OObj >
    void OVectObj<OObj>::destroy( iterator a , iterator b )
    {
    for( ; a != b ; ++a )
    {
    (&*a)->~OObj();
    }
    }

  •  (&*a)->~OObj();
    Joli ! :))
  • Je suis étonné que personne ne m'ait objecté que c'est celui qui fait new qui doit faire delete.
    C'est généralement ce qui est recommandé, puisqu'il est plus facile de savoir qui a l'ownership comme ça. Mais il y a des cas où ce n'est pas le cas, comme par exemple std::unique_ptr et std::shared_ptr (dont les objets sont crées en dehors de la classe, dans des factories std::make_unique et std::make_shared). Ou un autre exemple : boost::ptr_vector. Qui est exactement ce que tu fais.
    Donc non, cela a un sens ici de ne pas forcement respecter cette règle :)
Connectez-vous ou Inscrivez-vous pour répondre.