2017-09-17 4 views
1

Numéroté certains mémoire-Je ne comprends pas le travail de placement nouvelle et comment libérer la mémoire

buf = new char[sizeof(student_rec)*5];//student_rec is class 

Ensuite, créez un tableau de classe « student_rec » en utilisant le placement nouveau.

student_rec *sr1; 
sr1 = new(buf)student_rec[5]; 

Appelez la méthode fun() pour chaque classe.

for(i=0; i<5; i++) 
{ 
    sr1[i].fun(); 
} 

Ensuite, appelez le destructeur pour chaque classe.

i = 5; 
while(i) 
    sr1[--i].~student_rec(); 

Et de supprimer le bloc de mémoire alloué en utilisant supprimer.

delete [] buf; 

Alors pourquoi après avoir utilisé sr1 [2] .fun(), il affiche 'bonjour'? Lorsque je supprime la mémoire en utilisant delete [] buf, il n'y a pas de mémoire pour l'objet. Alors pourquoi sr1 [2] fonctionne bien?

Voici mon code-

class student_rec 
{ 
    private: 

     string name; 
     int roll_no; 
     float percentage; 

    public: 

     student_rec() 
     { 
      cout<<"zero argument constructure\n"; 
     } 

     ~student_rec() 
     { 
      cout<<"destructure\n"; 
     } 

     student_rec(char *n, int r, float per) 
     { 
      cout<<"three argument constructure\n"; 
      name = n; 
      roll_no = r; 
      percentage = per; 
     } 

     void show() 
     { 
      cout<<"Name= "<<name<<endl; 
      cout<<"Roll No.= "<<roll_no<<endl; 
      cout<<"Percentage= "<<percentage<<endl; 
     } 

     void fun() 
     { 
      cout<<"hello\n"; 
     } 

}; 

int main() 
{ 
    char *buf; 
    buf = new char[sizeof(student_rec)*5]; 
    student_rec *sr1; 
    sr1 = new(buf)student_rec[5]; 
    int i; 
    for(i=0; i<5; i++) 
    { 
     sr1[i].fun(); 
    } 
    i = 5; 
    while(i) 
     sr1[--i].~student_rec(); 
    delete [] buf; 
    sr1[2].fun(); 
    return 0; 
} 
+5

L'accès à la mémoire supprimée est [comportement indéfini] (https://en.wikipedia.org/wiki/Undefined_behavior). Autrement dit, tout peut arriver: vous pouvez obtenir des zéros, des résultats précédents, des éléphants roses ou la culotte de votre copine. Demander pourquoi vous voyez ce que vous voyez est interdit par la norme C++;) – Drop

+1

En savoir plus sur [undefined behavior] (https://en.wikipedia.org/wiki/Undefined_behavior). La suppression d'un objet ne l'efface pas. –

+0

Pour préciser, "ne pas effacer un objet" est également une option pour le résultat du comportement indéfini, car, fondamentalement, est tout autre événement possible dans l'univers. En outre, vous pouvez obtenir des résultats différents en mode débogage/relâchement ou sur un autre système d'exploitation ou un compilateur ou une bibliothèque standard ou à un autre moment de la journée, ou s'il pleut. Ok, je pense que je me suis fait clair;) – Drop

Répondre

1

Comme les commentaires déjà mentionnés: Ce que vous faites est « un comportement non défini ». Mais pour votre cas particulier, votre fonction fun() n'a pas accédé à un membre de données de votre classe et n'est pas non plus une méthode virtual, donc rien de votre objet ne sera utilisé et donc cela fonctionne assez bien, même si vous allez effacer votre mémoire, car il n'y a vraiment rien dans la mémoire des objets, ce qui est nécessaire pour appeler cette fonction. Comme ceci, vous pouvez faire de cette méthode un static auquel on peut accéder sans un objet de cette classe.

Le compilateur connaît le type de votre pointeur student_rec et il sait également qu'il n'y a pas d'accès à un objet de sorte qu'il appellera simplement la méthode sans aucun accès aux données dans votre mémoire allouée et libérée.

Le code suivant fonctionne également, mais est aussi un comportement non défini:

class Bla 
{ 
    public: 
     void fun() { std::cout << "Hallo" << std::endl; } 
}; 

int main() 
{ 
    Bla* ptr=0; 

    ptr->fun(); // access of 0 pointer? No-> no data access, simply function call! But never do that in real code ;) 
} 

La méthode est du point de vue de la logique partie de la classe et non des objets. Comme vous pouvez le voir, nous ne créons jamais une instance de la classe, mais le code fonctionnera également dans la plupart des cas.

Sur gcc 6.1, il compile et fonctionne également avec -O0, donc il ne dépend pas du tout de l'optimisation. Aucun accès aux données d'objet, donc cela fonctionne sans objet. Mais rappelez-vous: Ceci est un code invalide parfait! :-)

Editer: Des commentaires: Pourquoi valgrind n'a pas attrapé de telles erreurs?

Assez simple: Si nous examinons les détails de ce que fait un compilateur à partir d'une méthode, nous obtenons quelque chose comme ça: (pseudo code!)

class Bla { void fun() { ... } }; 

se traduit à l'interne:

Bla::fun(Bla* this) { ... } 

En fonction de la mise en oeuvre du compilateur, typiquement le premier paramètre de fonction est le pointeur vers l'objet lui-même. Donc l'appel de fun() entraîne l'appel de Bla :: fun (this); À ce stade, il est totalement indépendant de la valeur de ceci! Donc, si, comme indiqué dans mon exemple de code ci-dessus, c'est 0! Et à l'intérieur de Bla :: fun() rien n'accède à ce pointeur. Donc le code semble être valide!

Valgrind se vérifie uniquement sur l'exécutable lui-même, de sorte valgrind ne trouvera pas un accès invalide des membres de données, car il trouve tout simplement pas accès valable du tout :-)

« si cela fonctionne, quelle est la différence avec les fonctions statiques? "

Si la méthode est définie comme statique, le compilateur génère une fonction sans le pointeur this. Donc c'est différent.

"Et comment allons-nous jamais suivre ces erreurs?"

Si votre méthode n'est pas static mais n'a pas accédé à un membre de données, il s'agit d'un défaut de conception. Je ne peux pas voir une raison pour laquelle nous devrions avoir une méthode sans accès aux données d'objets du tout qui n'est pas déclarée statique.

Mon conseil est ici, pour vérifier si vous avez de telles méthodes non statiques? Mais oui, je ne savais pas si un compilateur pouvait générer un avertissement sur ces méthodes.

+0

C'est bizarre. Même 'valgrind' ne s'en plaint pas. Si cela fonctionne, quelle est la différence avec les fonctions 'static'? Et comment allons-nous jamais suivre ces erreurs? – Chiel

+0

@Chiel: C'est un peu comme la différence entre une fonction membre 'const' et une fonction non-'const' qui ne change aucun champ. – einpoklum

+0

@einpoklum: Le fait de ne pas modifier les membres de données ne signifie pas que vous n'accédez pas aux membres de données. Donc le code ci-dessus va planter aussi avec un accès const si le pointeur this n'est pas valide (0 dans mon exemple!). Je ne peux pas saisir le point, où votre comparaison entre statique et const aide sur ce sujet. – Klaus