Partage
  • Partager sur Facebook
  • Partager sur Twitter

new et delete dans une fonction

    11 octobre 2021 à 9:56:43

    Bonjour,

    je me pose la question de comment utiliser delete dans un cas précis

    Voici un programme pour exemple

    #include <iostream>
    #include <array>
    #include <algorithm>
    
    using _array = std::array<int, 7>;
    
    auto print = [](_array &v)->void {
      std::cout << "-> ";
      for (auto &value : v)
      {
        value++;
        std::cout << value << ' ';
      }
    };
    _array pointeur() noexcept
    {
      _array *ptr = new _array;
      *ptr = {5,6,2,9,0,10,3};
      
      return *ptr;
      delete [] ptr;
    }
    
    int main()
    {
      _array p = pointeur();
      std::sort(std::begin(p), std::end(p));
      std::copy(std::begin(p), std::end(p), std::ostream_iterator<int>(std::cout << "-> ", " "));
      std::cout << '\n';
      print(p);
    
      std::cout << std::endl;
      return 0;
    }

    et j'obtiens en sortie ce que je souhaite

    $ ./main
    -> 0 2 3 5 6 9 10 
    -> 1 3 4 6 7 10 11 

    Si j'utilise valgrind pour voir s'il y a des fuites de mémoire j'ai ceci :

    $ valgrind --leak-check=full ./main
    ==4662== Memcheck, a memory error detector
    ==4662== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==4662== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
    ==4662== Command: ./main
    ==4662== 
    -> 0 2 3 5 6 9 10 
    -> 1 3 4 6 7 10 11 
    ==4662== 
    ==4662== HEAP SUMMARY:
    ==4662==     in use at exit: 28 bytes in 1 blocks
    ==4662==   total heap usage: 3 allocs, 2 frees, 73,756 bytes allocated
    ==4662== 
    ==4662== 28 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==4662==    at 0x4843FB3: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4662==    by 0x1098A2: pointeur() (main.cpp:17)
    ==4662==    by 0x1091EB: main (main.cpp:26)
    ==4662== 
    ==4662== LEAK SUMMARY:
    ==4662==    definitely lost: 28 bytes in 1 blocks
    ==4662==    indirectly lost: 0 bytes in 0 blocks
    ==4662==      possibly lost: 0 bytes in 0 blocks
    ==4662==    still reachable: 0 bytes in 0 blocks
    ==4662==         suppressed: 0 bytes in 0 blocks
    ==4662== 
    ==4662== For lists of detected and suppressed errors, rerun with: -s
    ==4662== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
    

    Donc si je comprends tout bien je perds 28 bytes dans un bloc ce qui veut dire que le delete dans la fonction ne sert à rien. Mais en même temps je ne sais pas où le placer.

    Qu'en pensez vous ?

    • Partager sur Facebook
    • Partager sur Twitter
      11 octobre 2021 à 10:08:01

      Tu effectues ton delete après le return, hors aucune instruction n'est exécutée après un return.

      Il faut donc que l'appelant de pointeur() appelle lui-même delete une fois qu'il en a fini avec ton pointeur.

      Par contre, pourquoi retourner un pointeur sur un std::arrray ?

      • Partager sur Facebook
      • Partager sur Twitter

      Si vous ne trouvez plus rien, cherchez autre chose.

        11 octobre 2021 à 10:11:15

        Salut,

        1- Rien de ce qui se trouve après un return ne sera exécuté

        2- Tout ce qui doit être exécuté doit se trouver AVANT le return

        3- oublie cette histoire de pointeur (surtout avec une donnée de types std::array): si tu dois renvoyer quelque chose, renvoie le de préférence sous forme de référence (éventuellement constante)

        4- Quand on renvoie un pointeur (non nul) sur une donnée, il faut ABSOLUMENT s'assurer que la donnée se trouvera à l'adresse indiquée aussi longtemps que le pointeur est utilisé.

        5- on ne met jamais new et delete dans une même fonction

        6- on n'utilise pas new et delete pour les données membres, à moins que l'on n'ait vraiment pas le choix

        7- dans le pire des cas, on placera le new dans le constructeur (ou dans une fonction qui sera -- idéalement -- appelée par le constructeur) et le delete  dans le destructeur (ou dans une fonction qui sera appelée par le destructeur). On est alors soumis à  la règle anciennement connue sous le nom de Big Three Rule (désormais connue sous le nom de Big Five Rule)

        • Partager sur Facebook
        • Partager sur Twitter
        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
          11 octobre 2021 à 14:17:43

          De toute façon en C++ moderne on n'utilise pas new ni delete à moins d'avoir une raison valable de le faire.
          • Partager sur Facebook
          • Partager sur Twitter

          git is great because Linus did it, mercurial is better because he didn't.

            11 octobre 2021 à 16:24:04

            Merci pour toutes ces infos et conseils
            • Partager sur Facebook
            • Partager sur Twitter
              11 octobre 2021 à 20:06:25

              Beaucoup plus simple

              _array pointeur() noexcept
              {
                return  {5,6,2,9,0,10,3};
              }

              Explication:

              • le type de retour de la fonction étant déclaré _array, le compilateur déduit que ce qui suit return désigne un objet de ce type
              • et que {5, 6, ... } est un initialisateur de cet objet
              • ce qui appelle donc le constructeur avec liste d'initialisation
              vector (initializer_list<value_type> il,
                     const allocator_type& alloc = allocator_type());
              
              PS: c'était déjà présent dans  *ptr = { .... };

              -
              Edité par michelbillaud 11 octobre 2021 à 20:09:32

              • Partager sur Facebook
              • Partager sur Twitter

              new et delete dans une fonction

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown