Почему деструктор не вызывается для переменной стека при использовании присваивания? - PullRequest
3 голосов
/ 24 января 2020

Этот глупый код уже занял у меня 2 часа, я не могу понять, почему не вызывается деструктор первого элемента, размером 7,? Что происходит с памятью, выделенной для new uint16_t[7]?

#include <iostream>

using namespace std;

struct Node
{
    Node(uint16_t n) : p(new uint16_t[n]) {
        cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
        for(uint16_t i=0; i<n; i++) p[i] = n;
    }

    ~Node() {
        cout<<"Destructor for p[0] = "<< *p <<" with memory addr: "<<p<<endl;
        delete[] p;
    }

    uint16_t *p;
};

int main()
{
    {
        Node nd1(7);
        {
            nd1 = Node(3);
            cout << "1st place holder" << endl;
        }
        cout << "2nd place holder" << endl;
    }

    return 0;
}

Вывод

Constructed with size= 7, memory addr: 0x158cc20                                                                                                                                   
Constructed with size= 3, memory addr: 0x158cc40                                                                                                                                   
Destructor for p[0] = 3 with memory addr: 0x158cc40                                                                                                                                
1st place holder                                                                                                                                                                   
2nd place holder                                                                                                                                                                   
Destructor for p[0] = 0 with memory addr: 0x158cc40                                                                                                                                
*** Error in `./a.out': double free or corruption (fasttop): 0x000000000158cc40 ***                                                                                                
Aborted (core dumped) 

Ответы [ 2 ]

5 голосов
/ 24 января 2020

Я не могу понять, почему деструктор первого элемента, размером 7, не называется?

Это называется . Фактически, это тот деструктор, который заставляет программу создавать sh. Поведение программы не определено, поскольку деструктор удаляет то же значение указателя, которое ранее было удалено деструктором временного объекта. А также до этого он перенаправляется через этот недействительный указатель.


Что происходит с памятью, выделенной для нового uint16_t [7]?

Указатель на память был потерян при назначении объекта. Это называется утечкой памяти.

3 голосов
/ 24 января 2020

Этот код: nd1 = Node(3); не соответствует вашим ожиданиям.

Он не заменяет nd1 на Node(3) и убивает старого nd1.

Он создает новый временный экземпляр узла Node(3) и копирует значение каждого члена в nd1. Таким образом, и временный, и nd1 содержат указатель, указывающий на один и тот же адрес. В этот момент вы вытекли из памяти nd1, выделенной в начале программы, поскольку на нее не ссылается ни один указатель, но вы не удалили ее.

Когда временный элемент умирает, nd1 указывает на мертвый Память. Когда nd1 запускает свой деструктор на втором }, он снова удаляет тот же указатель, следовательно, ваша ошибка.


Чтобы исправить это, вам нужно будет реализовать то, что называется правилом пяти или правило нуля.

Самым простым является правило нуля. Просто используйте unique_ptr и уничтожение произойдет, как и ожидалось:

struct Node
{
    Node(uint16_t n) : p(std::make_unique<uint16_t[]>(n)) {
        cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
        for(uint16_t i=0; i<n; i++) p[i] = n;
    }

    std::unique_ptr<uint16_t[]> p;
};

int main()
{
    {
        Node nd1(7);
        {
            nd1 = Node(3); // assignement destroys the old buffer
            cout << "1st place holder" << endl;
        }
        cout << "2nd place holder" << endl;
    }

    return 0;
}
...