2016-01-22 7 views
1

Я работаю над книгой Stroustrup C++ 11, и я столкнулся с двойным свободным исключением. Я понимаю, что это освобождение памяти в два раза, но то, что я не понимаю, почему это происходит для функции, которая проходя мимо копии:C++ double free error from function copy

#include <iostream> 

using namespace std; 

namespace ALL_Vector { 

    class Vector { 
    public: 
     // Intitialize elem and sz before the actual function 
     Vector(int size) :elem {new double[size]}, sz {size} {}; 
     ~Vector() {delete[] elem;}; 

     double& operator[](int i) { 
     return elem[i]; 
     }; 
     int size() {return sz;}; 
    private: 
     double* elem; 
     int sz; 
    }; 


    void print_product(Vector& y) { 
    double result {1}; 

    for (auto x = 0; x < y.size() ; x++){ 
     if (y[x] > 0) {result *= y[x]; }; 
    } 

    cout << "The product of Vector y is: " << result << ", or so it would appear ;)\n"; 
    } 

} 


/* 
    Self test of the Vector class. 
*/ 

int main(){ 
    ALL_Vector::Vector myVector(15); 
    cout << "The size of Vector y is: " << myVector.size() << "\n"; 
    myVector[0] = 12; 
    myVector[2] = 7; 
    myVector[3] = 19; 
    myVector[4] = 2; 

    ALL_Vector::print_product(myVector); 

    return 0; 
} 

print_product() принимает вектор класса и создавая новый вектор с дублируется содержание? Почему это приведет к двойному освобождению? Я предполагаю, что RIIA в этом случае каким-то образом взаимодействует с Vector :: ~ Vector(), что-то вроде состояния гонки?

Я знаю, если я изменю это, чтобы передать его аргумент по ссылке, он избежит двойного освобождения. Я пытаюсь лучше понять проблему с передачей по копии.

Спасибо!

+0

Этот код работает [штраф] (https://ideone.com/ImpImv). –

+0

@LeFlou: У этого есть ошибка, которую тест не обнаруживает, а именно это нарушает правило трех. Интересно, что в вашем комментарии говорится, что код работает нормально, тогда ваш ответ объясняет, почему это не^_^ –

ответ

5

Фактически вы вызываете print_product со ссылкой на myVector, поэтому все в порядке.
Сложности начинаются с передачи myVector по значению, поскольку конструктор копии по умолчанию копирует elem указатель вместо дублирования всего массива.
Оба указателя ALL_Vector::Vectorelem будут ссылаться на одно и то же место для хранения и, следовательно, быть удалены дважды.
Чтобы решить эту проблему, вам необходимо реализовать конструктор копирования для создания нового массива и копирования всех элементов.

+0

Отличное объяснение, и это объясняет, почему работа по ссылке будет работать. Когда моя новая копия уничтожается в конце вызова функции, она освобождает память. Поэтому я ожидаю, что любые дополнительные ссылки на исходный объект будут иметь дамп ядра, поскольку выделенная память уже уничтожена. – MrMowgli

1

Если вы передадите Vector за значение, вызывается конструктор копирования, а не реализованный вами конструктор. В этом случае elem не дублируется, но указатель копируется в новый объект и затем дважды удаляется деструктором. Вы должны реализовать конструктор копирования, который выделяет новый elem и копирует все элементы.