C
C
calculator2122022-03-15 10:34:38
C++ / C#
calculator212, 2022-03-15 10:34:38

How to free memory properly?

My code
#include <iostream>
template <class T>
class Array
{
private:
    int m_length;
    T *m_data;

public:
    Array()
    {
        m_length = 0;
        m_data = nullptr;
    }

    Array(int length)
    {
        m_data = new T[length];
        m_length = length;
    }

    ~Array()
    {
        delete[] m_data;
    }

    void Erase()
    {
       delete[] m_data;
       m_data = nullptr;
       m_length = 0;
    }


    T& operator[](int index)
    {

        return m_data[index];
    }

    int getLength(){return m_length;}
};

int main()
{
    Array<Array<int>> ArrayArray(1);
//    ArrayArray[0] = *new Array<int>{10};
    ArrayArray[0] = Array<int>{10};
    return 0;
}


The problem is that if I allocate memory like this "ArrayArray[0] = *new Array{10};", then everything works fine, if without new, then the application crashes with double free detected in tcache 2. How to make it correct worked with this initialization " ArrayArray[0] = Array{10};".

Answer the question

In order to leave comments, you need to log in

2 answer(s)
E
Evgeny Shatunov, 2022-03-15
@calculator212

Let's take a look, first, at the line below the comment.
ArrayArray[0] = *new Array<int>{10};
What's going on here.
ArrayArray[0]will return a reference to Array<int>.
*new Array<int>{10}allocates memory on the heap under Array<int>, calls the initializer Array<int>::Array(int length), and then dereferences the resulting pointer to Array<int>. After that , the default copy operator will be executed
for the prepared reference to , the functionality of which will simply copy the fields from the object on the right to the object on the left of the assignment. After that, the result becomes leaked, because the pointer to it immediately becomes lost and it becomes impossible to free the memory occupied by it. For this reason with this line at you "everything fulfills normally". And no, everything does not work out for you normally because the memory has leaked.Array<int>
Let's look at the next line.
ArrayArray[0] = Array<int>{10};
What's going on here.
ArrayArray[0]will return a reference to Array<int>.
Array<int>{10}initializes an unnamed local object on the stack using the Array<int>::Array(int length).
After that, the default move operator is executed, the essence of which again boils down to copying the fields from the object on the right to the object on the left. After that, both objects refer to the same allocated memory via the field T *m_data.
The unnamed local object is then destroyed, freeing the newly allocated memory. And ArrayArray[0]at this moment it starts to refer to the freed memory.
Double deletion occurs when ArrayArrayat the end of the program it tries to delete already freed memory in ArrayArray[0].
There is a violation in your codetype invariant .
What should be done.
It should be clear to you by now that the problem in your code is related to the default behavior of the copy and move operators. But your problem is actually much broader. Because tomorrow you will also definitely want to carry out copy initialization or return an object by value from a function. In this case, you are also in trouble.
The solution to your problems is to follow the 3/5/0 rule .
You need to fully describe the behavior of objects when copying, moving, as well as when initializing with a copy and initializing through moving.

W
Wataru, 2022-03-15
@wataru

In the destructor, delete only if the memory is not nullptr or the length is not 0.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question