Почему срабатывает деструктор?

310
25 февраля 2017, 05:17

clarray.h

 #ifndef CLARRAY_H
 #define CLARRAY_H
 #include <iostream>
 #include <QString>
 using std::cout;
 using std::cin;
 using std::endl;
 class array
 {
 private:
    int* ptr;
    int size;
    QString name = "tmp_obj";
 public:
    array(int s, QString name){
        size = s;
        ptr = new int[s];
        this->name = name;
    }
    array(int s, int* p){
        size = s;
        ptr = p;
    }
    ~array(){
        cout << "destructor " << name.toStdString() << endl;
        delete[] ptr;
     }
     int& operator[](const int& j){
        return *(ptr+j);
      }
     array operator=(const array& cl){
        if(this!= &cl){
             size = cl.size;
             delete[] ptr;
             ptr = new int[size];
             *ptr = *cl.ptr; // для отладки пусть size == 1
         }
         cout << "= " << *this->ptr << endl;
         return *this;
    }
 };
 #endif // CLARRAY_H

main.cpp

#include <QCoreApplication>
#include <iostream>
#include <clarray.h>
using std::cout;
using std::cin;
using std::endl;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    const int ASIZE = 1;
    array *cl = new array(ASIZE, "c1");
    array *c2 = new array(ASIZE, "c2");
    for(int i = 0; i < ASIZE; i++)
        (*cl)[i] = i*i;
    *c2 = *cl;
    //сразу после присваивания срабатывает деструктор c2
    for(int i = 0; i < ASIZE; i++)
        cout << "c1: " << (*cl)[i] << " ";
    cout << endl;
    for(int i = 0; i < ASIZE; i++)
        cout << "c2: " << (*c2)[0] << " ";
    cout << endl;
    delete cl;
    delete c2;
   // return a.exec();
}

Output

= 0
destructor c2
c1: 0
c2: -572662307
destructor c1
destructor c2

Ещё кидает исключение _crtisvalidheappointer(block), как я понимаю из-за того что я обращаюсь к освобожденному участку памяти.

Вопрос: почему сразу после присваивания срабатывает деструктор?

Answer 1

Оператор присваивания данного класса возвращает временный объект, который и удаляется после вызова этого оператора присваивания.

 array operator=(const array& cl){
 ^^^^^^
    if(this!= &cl){
         size = cl.size;
         delete[] ptr;
         ptr = new int[size];
         *ptr = *cl.ptr; // для отладки пусть size == 1
     }
     cout << "= " << *this->ptr << endl;
     return *this;
}

Кроме того в результате данного предложения

*ptr = *cl.ptr; // для отладки пусть size == 1

имеется утечка памяти.

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

Что касается вызова деструктора, то вам следует объявить оператор присваивания следующим образом, то есть возвращать ссылку на объект

 array & operator=(const array& cl);
      ^^^

Данный конструктор

array(int s, int* p){
    size = s;
    ptr = p;
}

также неверный, так как объект класса должен динамически выделять память для своего массива. Иначе возникает коллизия: кто является владельцем указателя, и кто ответственен за удаления массива, адресуемого указателем?

К тому же вам следует также определить конструктор копирования.

Что касается конструкторов, то вы могли бы определить их следующим образом

#include <algorithm>
//...
array(int s, QString name) : size( s ), name( name )
{
    ptr = new int[s];
    std::fill( ptr, ptr + size, 0 );
}
array(int s, int* p) : size( s )
{
    ptr = new int[s];
    std::copy( p, p + s, ptr );
}
Answer 2

Ну смотрите сами: что возвращает ваш оператор?

array operator=(const array& cl){
     ...
     return *this;
}

Именно! array, а не ссылку на него. Так что return *this; вызывает конструктор копирования, и возвращает копию - объект array... который тут же уничтожается - он вам оказался не нужен.
Ну, а раз конструктора копирования у вас нет, то вызывается конструктор копирования по умолчанию - который копирует указатель (т.н. поверхностное копирование). Деструктор его удаляет, и ваш с1 остается с указателем на удаленную память...

Вот и всё.

READ ALSO
Qt | SQLite и QSqlTableModel

Qt | SQLite и QSqlTableModel

У меня есть таблицаКласс Table, унаследованый от QTableWidget и есть база данных

422
Проблема прокрутки MFC

Проблема прокрутки MFC

Здравствуйте, возникла проблема при подключении полосы прокрутки к окнуВ общем в окне рисуется график, при этом координаты смещаются с помощью...

300
Не могу определить &ldquo;GestureID&rdquo; в условии &ldquo;if&rdquo;

Не могу определить “GestureID” в условии “if”

При компиляции под win64 все работает корректноПри компиляции под Android вылетает ошибка:

252
Удаление MySQL Community Server

Удаление MySQL Community Server

Доброго времени сутокКак мне удалить MySQL полностью? При запуске Installer'a появляется такое окно:

359