Les 20 lignes de la honte

5 avril 2009 · Posted in C / C + + , Opinion

Alors que le riz cuit, je me suis souvenu d'un cas curieux de ce qui m'est arrivé au début de sa carrière, impliquant la gestion de la mémoire en C + +. A cette époque, j'étais beaucoup plus. Débutant Jeune, plus rapide, plus arrogant et plus ...

Un plus expérimentés collègue était d'expliquer à un autre collègue moins expérimenté que pour chaque nouvelle il doit y avoir une suppression correspondante. Sinon, l'objet sera persistent dans la mémoire et il peut y avoir des fuites de mémoire.

A ce stade, je l'ai interrompu et a dit "non pas nécessairement parce qu'il suffit que l'objet hors de portée pour le destructeur est appelé automatiquement .."

Depuis roulé un débat min 10 avec des arguments et des contre-arguments, et toute l'équipe reste à regarder. En fin de compte, la moitié de l'équipe d'accord avec lui et l'autre moitié avec moi, et à ce moment, personne n'avait à l'esprit un moyen de vérifier. Rechercher sur Internet n'était pas une option.

Comme j'ai eu toutes les réponses, après tout déjà programmé en PHP, Java et C + + était de montrer plus tard que j'avais raison.

Quelques jours plus tard, un de ces moments philosophiques, je me souvenais que d'une adresse mémoire est un numéro, et vous pouvez soit convertir une adresse à un numéro commun, et aller dans l'autre, bien que ce dernier est généralement inutile.

Puis j'ai imaginé un moyen de prouver ma théorie: Il serait de créer un objet dans un champ limité à l'affectation de nouvelles. Enregistrer l'adresse de cet objet comme un numéro commun dans un hors temps de la portée limitée, attendez-vous pour finaliser la portée limitée, le destructeur de obejto être appelé et puis le champ extérieur, utiliser le nombre qui représente l'adresse de l'objet pour accéder à ce domaine de la mémoire montrant que recevoir un SIGSEGV (segmentation fault) en essayant d'accéder à une zone mémoire invalide. Ensuite, j'ai généré le code ci-dessous.

  Une
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
  # Inclure
 # Include <string>

 using namespace std;

 int argc, char ** argv ) { int main (int argc, char ** argv) {
     0 ; unsigned long a = 0;

     {
         new string ( "Hello World!!!" ) ; * Str = new String ("Bonjour le monde!");
         unsigned long ) str ; a = (unsigned long) str;

         "str: " << str << endl ; cout <<"str:" <<str <<endl;
         "num: " << num << endl ; cout <<"num:" <<a <<endl;
     }

     * ( ( string * ) num ) << endl ; cout <<* ((* ​​string) a) <<endl;

     ; return 0;
 } 

Voici, à ma grande surprise le programme n'a pas explosé au visage. Il fonctionnait correctement en soulignant que, en fait j'ai été celui qui avait tort.

Recherche plus je réalisais que oui, il doit être nouveau pour chacun d'eux et que les supprimer, et plus pour chaque nouveau [] doit être une et une seule delete []. Qu'est-ce que je pensais que je savais sur la gestion mémoire et de la portée, il était probablement une certaine confusion entre les différentes langues.

Quand j'ai commencé la journée de discussion, avant, j'ai fait toutes les erreurs de base qui engage un débutant:

  1. Meddle où il a été appelé.
  2. Assermentation debout ce qui est juste sans preuve.
  3. Sous-estimer la connaissance de quelqu'un de plus expérimenté.
  4. Pensez-vous avoir toutes les réponses juste parce qu'ils viennent le voir en classe.
  5. Pour penser que juste parce qu'ils connaissent les rudiments de plusieurs langues, alors vous avez toutes les réponses.

Comme tout bon membre de l'espèce Homo sapiens , a parlé merde. Ma réaction à cette découverte a été de prendre toute l'équipe et je me suis trompé, excuses pour parler non-sens et montrent que ces vingt lignes de code utilisé pour le démontrer. Par ailleurs, je l'ai montré de toutes les sources que j'ai vérifié, et même fait sortir d'autres détails sur la gestion de la mémoire que nous fuyaient, comme les références circulaires . Cela a conduit à une ré-desing de certaines parties du projet.

Mes 20 lignes cógigo devint connu comme «Les 20 lignes de la honte" et donc j'ai été natual vissé. Chaque fois que quelqu'un avait des doutes parlé "il ya 20 lignes de vegonha pour les tests." Le sens était quelque chose comme «il ya un test simple pour ne pas être gêné plus tard."

La chose la plus importante est que mon post-chier attitude a été bien reçu et apporté des avantages à l'équipe. Si j'avais eu peur, tôt ou tard, quelqu'un serait prouver que je n'allait pas devant tout le monde, ou pire, dans les coulisses. Admettre leurs erreurs et apprendre de lui montré que j'étais prêt à être contestée. En plus de cette équipe a montré que plus je semble arrogant (je ressemble plus que je suis ...), je savais qu'il était un homme ordinaire qui a fait des erreurs comme tout le monde, je ne pense pas plus que quiconque. Cela a ouvert la voie à d'autres membres de l'équipe, n'hésitez pas à faire la même chose et nous devenons une équipe plus cohésive.

Commentaires

  • Marcus Antonius

    Très intéressante histoire!
    Plus bagages pour ceux qui ont suivi le débat!

    Une autre chose intéressante est l'absence de 18 jours pour la nouvelle version d'Ubuntu!
    (Mais c'est l'heure ?????????? mouches!)

  • http://blabos.org bavarder

    Dernièrement, pour moi time're ne vole pas goin téléportation, ...

  • Junio

    Blaber, merci de passer l'expérience. Très texte riche. Paix et santé pour vous.

  • ♣ ♦ ♥ ♠ Hime Cheshire

    Hmm ... Je ne suis pas sûr de ce compilateur que vous utilisez ou quelle version de la langue, mais je sais, C ne pas afficher les erreurs lors de l'accès de la mémoire libérée si elle est protégée par le système d'exploitation ... Le C + + affiche?

  • Blaber http://blabos.org des bleb

    Merci d'abord pour la visite!

    Il est C + + avec g + +, petit padawan :)

    Cela dépend de ce que vous considérez «erreurs d'affichage".

    Au moment de la compilation ou d'exécution?

    Dans le cas ci-dessus, l'inexpérience attendus (cacophonique cela!) Champ de sortie de destruction automatique (qui n'existe pas pour un objet alloué dynamiquement en C + +), suivie par un pointeur pointant derreferenciação à une zone (auparavant) de mémoire désallouée , provoquant une erreur fatale lors de l'exécution.

    Ajouter un delete str; après la ligne 14, vous remarquerez la subtile différence.

    Les deux tests ne donnent aucun avertissement à la compilation.

  • ♣ ♦ ♥ ♠ Hime Cheshire

    Non non, je parle dans le runtime même ... Au début, quand j'ai appris à programmer, notre professeur nous a enseigné vecteurs avant alloc, malloc et calloc, et donc, nous avons utilisé des vecteurs librement sans allouer de la mémoire ...

    Rarement donné une erreur de mémoire protégée du système d'exploitation ...
    En outre, toute erreur ne s'affiche pas, ou la compilation ou l'exécution.

    Bien sûr, il n'était pas avec des objets, c'est seulement avec C, dans les classes de la programmation structurée ... Donc ma question ... En C + +, en utilisant de nouvelles au lieu d'alloc, le programme génère des erreurs à l'exécution si j'essaie d'utiliser une mémoire non alloués?

    Je pense qu'il serait agréable de voir les spécifications de la langue, après tout, le destructeur, et désallouer la mémoire, vous pouvez le protéger jusqu'à l'achèvement du programme ou quelque chose ... ou qu'il ne se produise pas?

  • Blaber http://blabos.org des bleb

    Le terme "vecteur, nous avons utilisé librement sans allouer de la mémoire" est assez trompeuse, pour les tableaux de la mémoire ont besoin d'exister. Probablement que vous voulez dire "nous avons utilisé librement sans vecteurs allouer dynamiquement de la mémoire."

    La spécification dit derreferenciar une des résultats de pointeur NULL dans un comportement indéfini, qui dans la plupart des systèmes (mais pas tous), une erreur fatale.

    Ce n'est pas ce qui est montré ci-dessus. Dans l'exemple il ya une tentative d'accès à une zone de "prétendument" libérée.

    Pointeur NULL! = Pointeur de zone mémoire invalide.


    int* ptr_null = 0;

    / / Est un pointeur NULL ptr_null

    ptr_foo = new int * int (123456);
    supprimer ptr_foo;

    / / Points Ptr_foo à une zone de mémoire
    / / Qui n'appartient plus à ce programme

    printf ("% pn", ptr_null);
    printf ("% pn", ptr_foo);

    Compiler et exécuter les exemples, vous verrez la différence.

    Concernant le dernier paragraphe, non, ce n'est pas ce qui arrive. Vous mélangez les choses, le destructeur est simplement une routine qui est appelée automatiquement quand un objet est libérée, soit par un appel à delete des objets alloués dynamiquement sur ​​la production ou la portée des objets alloués sur le tas.

commentaires du blog propulsé par Disqus