Free memory of a variable that is pointer (doubt of nullptr)

1

I have a code that does the following:
look for a student because of his id, I have a student arrangement:

vector<Estudiante *> alumnos;

and I do the search by means of a function that contains a cycle, which is the following:

    for(Estudiante *alumno:this->estudiantes) {
    if((alumno->mostrarId() == id)) return alumno;

    return nullptr

now that function returns to the following variable:

Estudiante * incognito = nullptr

so what I do to know if there is a student with that id is to check that the variable does not have the value nullptr

Now my question is this: what do I do with the variable incognito after using it, do I have to eliminate it in some way? Do I have to leave it like that and memory is released alone? Am I so confused that I dedicate myself to sweeping instead of programming?

I tried delete incognito but did not compile me.

    
asked by soldat25 17.03.2017 в 04:25
source

3 answers

2
  

What do I do with the variable incognito after using it, do I have to eliminate it in some way?

No. The variable incognito is not deleted. This variable is a pointer to Estudiante so what you would do would be to free the memory that the variable is pointing to.

When should you free the memory pointed to by a pointer? .

When this memory has been created with the new operator.

The keyword nullptr represents a null pointer literal (in the same way as the zero ( 0 ) represents the additive identity in algebra). Since nullptr is a literal value that specifically identifies a null pointer, it has not been created by the operator new and therefore does not need to be removed by the operator delete .

Actually, if you delete nullptr , nothing happens . h3>

According to the C ++ standard , apply delete on a null pointer has no effect (translated and highlighted by me):

  

5.3.5 delete

     
  • If the operand value of the expression-delete is not a null pointer , then:

         

    (7.1) - If the value hosted by the expression-new for the object to be deleted was not omitted and its hosting has not been extended, the expression-delete you must call the un-host function. The value returned by the accommodation request of the expression-new must be passed as the first argument of the unsubscribe function.

         

    (7.2) - [...]

         

    (7.3) - Otherwise, the expression-delete will not call the unsubscribe function .

  •   

    The standard states that calling delete over a null pointer has no effect on free memory.

    In summary .

    You should not do anything with the variable incognito after using it, you should not do anything with the memory it points to because it is the null pointer (but if you delete the null pointer nothing would happen), you should only worry about releasing memory when it has been requested manually (using the operator new ).

        
    answered by 17.03.2017 / 09:04
    source
    2
      

    Am I so confused that I dedicate myself to sweeping instead of programming?

    hehe

    If you do

    void unafuncion( ) {
      int a = 10;
      ...
    }
    

    At some point would you release 10 ? No, because it is a literal . No It makes sense to release it, it is impossible. It is embedded in the source code of our program.

    Or would you release a ? Well either, because it is a local variable to the function; solita is already released.

    Well with nullptr it's the same. In itself it is a literal (== 0). It does not make sense to free it.

    All this comes from a theme, the pointers, which is durillo , but, if you think about it carefully, you'll see that it's simpler than it seems.

    struct Algo {
      char name[20];
      int temperatura;
    };
    

    What is temperatura ? From the point of view of the compiler, it is not more than a memory area, of a certain size, and that admits certain operations.

    We are the ones who add meaning semantic . I know that temperatura stores just that, referring to the city whose name I have stored in name . And, if I want my program to work, I have to be careful with what I store there, so that values are consistent to what I have decided to do with them .

    Well, the same thing happens with the pointers. For the compiler, a pointer is a data type like any other; It occupies a certain size, and certain operators can apply it. One of those operations is to use it as indirect access to a memory address, to read or write it.

    The semantic value of a pointer is our thing. The decision to assign the value 0 ; or use it to store the result of a search; or place the address of a memory block returned by new .

    All those things are interpretations that WE make the value of the pointer; the compiler does not know anything about it, and simply tells us if we try to do odd or incorrect things. For the compiler, the pointer remains a simple data, like any other.

    By this I mean that if you do int *alto = nullptr; , the compiler does not assume or know anything. Does not allocate memory; he just checks that the types are comparative, and to throw p'alante .

        
    answered by 17.03.2017 в 06:47
    2

    To put it in a context understandable by all, imagine the following scenario:

    class Listado
    {
      std::vector<Estudiante*> estudiantes;
    
      public:
        Estudiante* BuscarEstudiante(int id)
        {
          for(Estudiante *alumno:this->estudiantes)
            if((alumno->mostrarId() == id)) return alumno;
    
          return nullptr;
        }
    };
    
    void funcionCualquiera(Listado& listado)
    {
      Estudiante* estudiante = listado.BuscarEstudiante(id);
    
      // operaciones con la variable estudiante
      // ...
    
    
      // ¿Hay que hacer un delete sobre estudiante?
    }
    

    Regarding the comment of the penultimate line of the example, who has the responsibility to release the memory of the element? There is no clear standard in this respect but a series of guidelines can be followed to reduce misunderstandings:

    • Ideally, the person who makes the memory reservation should be in charge of releasing it. When reserves are made in the X code layer and the releases in the Y layer it can be difficult to trace the reserves and it is likely that the program will lose memory. This pattern applied to the example that I have put implies that it would be the class Listado responsible for releasing the memory (for example in the destructor):

      Listado::~Listado()
      {
        for( auto estudiante : estudiantes )
          delete estudiante;
      }
      
    • If the value returned by a function should not be released by the caller, it is advisable to return a reference or a copy of the object (whenever possible). It does not occur to anyone to throw a delete on a reference (because before you would have to convert it to pointer). Apply this to the function BuscarEstudiante is not a direct step, since you have to contemplate a mode of action for the case in which no results are found (you can not return a reference to nullptr ). One possibility may be to throw an exception:

      Estudiante& Listado::BuscarEstudiante(int id)
      {
        for(Estudiante *alumno:this->estudiantes)
          if((alumno->mostrarId() == id)) return alumno;
      
        throw std::out_of_range("No hay estudiantes con el id indicado");
      }
      
    • As far as possible, use smart pointers. These pointers were incorporated into the C ++ 11 standard. An intelligent pointer is nothing more than a package that is responsible for managing the life cycle of a pointer. There are two families to choose from:

      • unique_ptr : This wrapper is intended for non-shared pointers. You can not make copies and when the wrapper is destroyed your pointer dies with it:

        void func()
        {
          std::unique_ptr<Estudiante> estudiante(new Estudiante);
        
          // ...
        } // el puntero se destruye en este punto
        
      • shared_ptr : Wrapper designed for shared pointers. It allows making copies and the pointer is not destroyed until the last copy disappears:

        void func()
        {
          std::shared_ptr<Estudiante> estudiante(new Estudiante);
        
          {
            std::shared_ptr<Estudiante> copia = estudiante; // ok
        
            // ...
        
          } // copia se destruye pero estudiante no, el puntero sigue vivo
          // ...
        } // el puntero se destruye en este punto
        
    • Use common sense: There are a thousand specific situations related to pointers. To avoid problems, it is best to use common sense and leave those doubtful situations correctly commented to avoid misunderstandings. The most important thing is to decide who is the owner of the pointer at all times to be able to assign the responsibility to release the memory when appropriate. This point I have left on purpose for the end because it does not speak of concrete things but of rather abstract concepts. In the end, it will be the experience that dictates how you should solve these problems.

    answered by 17.03.2017 в 08:57