What is the problem of allocating memory with new and then not deleting?

5

What can happen if I use new to allocate memory and then not release it?

And when it is in the situation below, that I can not erase the allocated memory, since I need to return, what do I do?

const char* enc(const char* Str)
{
    auto len = strlen(Str);
    char* _Str = new char[len];

    for (size_t i = 0; i < len; i++) _Str[i] = Str[i] + 4;

    _Str[len] = '
const char* enc(const char* Str)
{
    auto len = strlen(Str);
    char* _Str = new char[len];

    for (size_t i = 0; i < len; i++) _Str[i] = Str[i] + 4;

    _Str[len] = '%pre%';
    return _Str;
}
'; return _Str; }
    
asked by anonymous 07.03.2018 / 01:35

3 answers

3

The role of the new operator is to allocate a region of memory (heap, not the execution stack) to the data, and invoke in each cell the constructor for that data type. This means that every time you run the new operator it takes up more memory and, as memory has a limit, you can not call new at will without using delete before memory is missing for another new .

Programs that need to do a lot of memory allocations (such as symbolic math programs, web servers, and so on) need to manage memory well, so they eliminate unnecessary data if that region of memory is needed for something later. Common programs that need to allocate a lot of data may also have problems like this, but it is less common.

Typically, in C ++ the data allocated in a scope is deallocated in it, which is a good programming practice based on variable life-time control and guarantees the deallocation of data no longer needed. In cases of data that need to persist in scopes above, the data is already built into or copied to the original scope variables.

In order to facilitate this control of the life time, it is usually used to construct structures and class objects in order to allocate the data whenever the objects are created and also the destructor to delete them, practically automating the control of the the lifetime of the data allocated in the heap without having to remember to use new and delete at the right time.

With this, you could make a structure like this.

struct StringType {
private:
    char *strChars ;
    size_t strLen ;
    void constroy( size_t len ){
        strChars = new char[ (strLen=len)+1 ] ;
    }
    void constroyCopy( const StringType &string ){
        constroy( string.StrLen ) ;
        for( size_t index=0 ; index<=StrLen ; index++ ){
            StrChars[index] = string.StrChars[index] ;
        }
    }
    void destroy( void ){
        delete strChars ;
    }
public:
    ~StringType( void ){
        destroy() ;
    }
    StringType( size_t maxLength ){
        constroy(maxLength) ;
    }
    StringType( const StringType &string ){
        constroyCopy(string) ;
    }
    resetString( size_t newMaxLength ){
        destroy() ;
        constroy(newMaxLength ) ;
    }
    resetString( const StringType &string ){
        destroy() ;
        constroyCopy(string) ;
    }
    size_t length( void ){
        return strLen ;
    }
    const char* charPointer( void ){
        return strChars ;
    }
}

And then if you want the data to persist by copy you do a function that returns the structure, then it will be copied.

StringType char* enc( const char* Str ){
    StringType _Str( strlen(Str) ) ;
    for( size_t i=0 ; i<_Str.length() ; i++ ) _Str.charPointer[i] = Str[i]+4 ;
    _Str.charPointer[len] = '
void enc( const char* Str , String *Str_out ){
    Str_out.resetString( strlen(Str) ) ;
    for( size_t i=0 ; i<Str_out.length() ; i++ ) Str_out.charPointer[i] = Str[i]+4 ;
    Str_out.charPointer[len] = '
auto len = strlen(Str);
char* _Str = new char[len];
'; }
'; return _Str ; }

But if you prefer better performance you can save the data directly into a destination structure by passing its address as an argument.

_Str[len] = '
void enc( const char* Str , char* _Str_out ){
    size_t len = strlen(Str) ;
    for( size_t i=0 ; i<len ; i++ ) _Str_out[i] = Str[i]+4 ;
    _Str_out[len] = '
void enc( const char* Str , char* _Str_out ){
    size_t i ;
    for( i=0 ; Str[i]!='
struct StringType {
private:
    char *strChars ;
    size_t strLen ;
    void constroy( size_t len ){
        strChars = new char[ (strLen=len)+1 ] ;
    }
    void constroyCopy( const StringType &string ){
        constroy( string.StrLen ) ;
        for( size_t index=0 ; index<=StrLen ; index++ ){
            StrChars[index] = string.StrChars[index] ;
        }
    }
    void destroy( void ){
        delete strChars ;
    }
public:
    ~StringType( void ){
        destroy() ;
    }
    StringType( size_t maxLength ){
        constroy(maxLength) ;
    }
    StringType( const StringType &string ){
        constroyCopy(string) ;
    }
    resetString( size_t newMaxLength ){
        destroy() ;
        constroy(newMaxLength ) ;
    }
    resetString( const StringType &string ){
        destroy() ;
        constroyCopy(string) ;
    }
    size_t length( void ){
        return strLen ;
    }
    const char* charPointer( void ){
        return strChars ;
    }
}
' ; i++ ) _Str_out[i] = Str[i]+4 ; _Str_out[i] = '
StringType char* enc( const char* Str ){
    StringType _Str( strlen(Str) ) ;
    for( size_t i=0 ; i<_Str.length() ; i++ ) _Str.charPointer[i] = Str[i]+4 ;
    _Str.charPointer[len] = '
void enc( const char* Str , String *Str_out ){
    Str_out.resetString( strlen(Str) ) ;
    for( size_t i=0 ; i<Str_out.length() ; i++ ) Str_out.charPointer[i] = Str[i]+4 ;
    Str_out.charPointer[len] = '
auto len = strlen(Str);
char* _Str = new char[len];
'; }
'; return _Str ; }
' ; }
'; }
';

Note: In this snippet of your code

_Str[len] = '
void enc( const char* Str , char* _Str_out ){
    size_t len = strlen(Str) ;
    for( size_t i=0 ; i<len ; i++ ) _Str_out[i] = Str[i]+4 ;
    _Str_out[len] = '
void enc( const char* Str , char* _Str_out ){
    size_t i ;
    for( i=0 ; Str[i]!='%pre%' ; i++ ) _Str_out[i] = Str[i]+4 ;
    _Str_out[i] = '%pre%' ;
}
'; }
';

You have allocated cells with 0, 1, ..., len-1 and in this

%pre%

You saved in the index cell len , which does not exist. To avoid possible errors (such as having something else allocated in that memory region that will be lost), allocate one more cell. In the codes I've made, I have already automated this by allocating% of cells% in constructing the string structure.

Any questions?

Edit: There is a workaround that preserves the way you program, does not require a deployed structure, and should perform better. All you have to do is add a parameter that is an array of target characters so that you write the solution in it instead of allocating and returning an array of characters. With this, you have all the control of creating and removing the data from outside the function, and may involve scopes or other criteria that you consider more appropriate.

%pre%

One more thing, you can do this without having to call the function that counts the number of characters in the string, thus improving performance.

%pre%     
07.03.2018 / 06:17
5

The "problem" is that every time the function is called, more memory is used. The problem is actually greater if your program will function as a server or other type of long-running process, and run for hours / days - and each call will use a little more memory.

If it is a quick, terminal interaction program that does something and ends, there is no problem - except for violating good programming practices.

Now, the interesting thing is this: in fact in systems of even medium complexity, normal functions that "create" objects that will be used elsewhere in the program do not deallocate this memory. It is the responsibility of the code that called the function that creates an object by allocating memory to destroy the created object. What to do in each case should be in the documentation of your function.

In this case, you just create a string - so just document that whoever calls this function should delete after using the return value - C ++ will actually destroy the string by itself if it goes out of scope in the where it was called - and this happens for strings or other objects. If the code were pure C, anyone using its function would have to be instructed or to call a function to destroy the object explicitly (necessary for structs containing pointers to other structs, for example), or directly call the function free . (In C ++, the delete command or the output of the scope calls the destructor of the object - a special method that does this action).

    
07.03.2018 / 01:47
0
Since you have used auto so you should be using at least C ++ 11 then you might consider returning a std::unique_ptr which ensures that there is only one copy of the pointer. So the user of your function does not have to worry about this because the deletion is done automatically when the pointer goes out of scope.

A little off topic, considering also the use of C ++ 11 (or greater) you should avoid the use of "raw" pointers as much as possible.

    
07.03.2018 / 10:30