2016-01-22 1 views
1

Je suis en train de travailler sur le livre Stroustrup C++ 11, et j'ai rencontré une double exception gratuite. Je comprends que cela libère la mémoire deux fois, mais ce que je ne comprends pas pourquoi ça se passe pour une fonction qui est en passant par copie:Double erreur C++ libre à partir de la copie de fonction

#include <iostream> 

using namespace std; 

namespace ALL_Vector { 

    class Vector { 
    public: 
     // Intitialize elem and sz before the actual function 
     Vector(int size) :elem {new double[size]}, sz {size} {}; 
     ~Vector() {delete[] elem;}; 

     double& operator[](int i) { 
     return elem[i]; 
     }; 
     int size() {return sz;}; 
    private: 
     double* elem; 
     int sz; 
    }; 


    void print_product(Vector& y) { 
    double result {1}; 

    for (auto x = 0; x < y.size() ; x++){ 
     if (y[x] > 0) {result *= y[x]; }; 
    } 

    cout << "The product of Vector y is: " << result << ", or so it would appear ;)\n"; 
    } 

} 


/* 
    Self test of the Vector class. 
*/ 

int main(){ 
    ALL_Vector::Vector myVector(15); 
    cout << "The size of Vector y is: " << myVector.size() << "\n"; 
    myVector[0] = 12; 
    myVector[2] = 7; 
    myVector[3] = 19; 
    myVector[4] = 2; 

    ALL_Vector::print_product(myVector); 

    return 0; 
} 

print_product() prend la classe Vector et la création d'un nouveau vecteur avec dupliqué Contenu? Pourquoi cela causerait-il un double gratuit? Je suppose que RIIA dans cette instance est en quelque sorte en interaction avec le Vector :: ~ Vector(), quelque chose comme une condition de concurrence?

Je sais que si je change cela pour passer son argument par référence cela évitera le double libre. J'essaie de mieux comprendre le problème en passant par copie.

Merci!

+0

Ce code fonctionne [bien] (https://ideone.com/ImpImv). –

+0

@LeFlou: Il a un bug que le test ne détecte pas, à savoir qu'il viole la règle de trois. Il est intéressant que votre commentaire indique que le code fonctionne bien alors votre réponse explique pourquoi ce n'est pas^_^ –

Répondre

5

En fait vous appelez print_product avec une référence à myVector, donc tout va bien.
Les problèmes commencent par le passage de myVector par valeur car le constructeur de copie par défaut copie le pointeur elem au lieu de dupliquer le tableau entier.
Les deux ALL_Vector::Vectorelem pointeur se référera au même stockage de mémoire et donc être supprimé deux fois.
Pour résoudre ce problème, vous devez implémenter le constructeur de copie pour créer un nouveau tableau et copier tous les éléments.

+0

Grande explication, et cela explique pourquoi passer par référence fonctionnerait. Lorsque ma nouvelle copie est détruite à la fin de l'appel de la fonction, elle libère la mémoire. Je m'attendrais donc à ce que toutes les références à l'objet original soient effacées car la mémoire allouée a déjà été détruite. – MrMowgli

1

Si vous transmettez Vector par valeur, le constructeur de la copie est appelé, pas le constructeur que vous avez implémenté. Dans ce cas, elem n'est pas dupliqué mais le pointeur est copié dans le nouvel objet puis supprimé deux fois par le destructeur. Vous devez implémenter un constructeur de copie qui alloue un nouveau elem et copie tous les éléments.