Исправлена ошибка double free или corruption, но почему это происходит? [дубликат]


На этот вопрос уже есть ответ здесь:

  • Что такое правило трех? 8 ответов

У меня есть следующий код:

src/main.cpp:

#include <include/array.hpp>

int main() {
    int temp[] = {1, 2, 3, 4, 5};
    sdizo::array<int> a(temp, 5);
    print_array(a);
    return 0;
}

include/array.hpp

#pragma once
#include <string.h>
#include <iostream>

namespace sdizo {

template <class T>
class array {
private:
    T* data;
    int length;

public:
    array();
    array(T* d, int len);
    ~array();
    T* begin();
    T* end();
};
template <typename T>
array<T>::array() {
    data = nullptr;
    length = 0;
}

template <typename T>
array<T>::array(T* d, int len) {
    length = len;
    this->data = new T[len];
    memcpy(this->data, d, sizeof(d[0]) * len);
}
template <typename T>
array<T>::~array() {
    delete[] this->data;
}
template <typename T>
T* array<T>::begin() {
    return &data[0];
}
template <typename T>
T* array<T>::end() {
    return &data[length];
}

template <typename T>
void print_array(array<T> ar) {
    for (auto x : ar) {
        std::cout << x << " ";
    }
    std::cout << 'n';
}
}

Компиляция его с помощью: g++ src/*.cpp -I./ -std=c++1z -g -o bin/sdizo1

Теперь запуск его дает следующую ошибку:

Введите описание изображения здесь

Я заметил, что когда я не печатал массив, то никаких ошибок не произошло. Я подумал о передаче массива по ссылке, потому что теперь он создаст локальную копию, и, возможно, ошибка была вызвана вызовом деструктора дважды. Так что void print_array(array<T> &ar) вместо void print_array(array<T> ar) сработало.

Теперь проблема исчезла, но почему это так? Я знаю, что, вероятно, ~array() был вызван дважды или что-то в этом роде, в одном и том же месте памяти, но почему. Разве компилятор C++ недостаточно умен, чтобы обнаружить такие вещи? Или я должен всегда проходить по ссылке, или есть способ пройти мимо значения и не получить такого рода ошибки со структурой с заказным деструктором? Я знаю, что это, вероятно, будет скучно для многих ppl умнее меня, но эй, тот, кто ничего не спрашивает, ничего не узнает.
1 2

1 ответ:

СмотритеПравило трех/пяти/нуля . У вас есть класс с необработанным указателем владельца. Конструктор копирования по умолчанию и оператор присваивания копирования не будут делать то, что вы ожидаете, они только копируют указатель. Два или более экземпляра имеют указатель на одни и те же данные, и каждый удаляет его.

Edit: чтобы пояснить, причина, по которой вы не замечаете проблему, когда вы изменяете print_array, чтобы взять его аргумент по ссылке, заключается в том, что вы не будете использовать дефектный конструктор копирования или назначение копирования оператор. Это не проблема с print_array, это дефект в классе array, который должен быть исправлен.