Войти

Показать полную графическую версию : От куда взялся деструктор?


zl3p
09-02-2007, 03:04
Решение этой проблемы меня уже порядком достало, поэтому решил спросить у профессионалов, знающих ООП.

Проблема собтвенно в том, что в следующем перезагруженном операторе выполняется 1 коструктор и 2 деконструктора. От куда берется второй деконструктор в этом коде:

vector vector::operator + (const vector &obj)
{
if (this->n != obj.n) cout << "Error: diff. dim\n";
vector tmp(obj.n);
for (long i=0; i<obj.n; i++) {
tmp.x[i] = this->x[i] + obj.x[i];
}
return tmp;
}

У меня здесь динамическое выделение памяти под объекты, и, естественно, что двухразовое выполнение delete ни к чему хорошему привести не может. Поэтому хочу устраниться данную ошибку. Ниже полный код проги:

#define real double
#include <conio.h>
#include <stdio.h>
#include <iostream.h>

//--------------
class vector
{
public:
real *x;
long n;
public:
vector();
vector(long);
~vector();
vector& operator = (const vector&);
vector operator + (const vector&);
};

vector::vector ()
{
n = 1;
x = new real[n];
cout << "constructor \n";
}

vector::vector (long dim)
{
n = dim;
if (n>0) x = new real[n];
cout << "constructor \n";
}

vector::~vector()
{
delete[] x;
n = 0;
cout << "destructor \n";
}

vector& vector::operator = (const vector &obj)
{
if (this->n != obj.n) cout << "Error: diff. dim\n";
for (long i=0; i<obj.n; i++) {
this->x[i] = obj.x[i];
cout << obj.x[i] << " , " << this->x[i] << "\n";
}
return (*this);
}

vector vector::operator + (const vector &obj)
{
if (this->n != obj.n) cout << "Error: diff. dim\n";
vector tmp(obj.n);
for (long i=0; i<obj.n; i++) {
tmp.x[i] = this->x[i] + obj.x[i];
}
return tmp;
}

//-----------
void main()
{
{
vector a(3);
vector b(3);
a + b;
}
getch();
}

//================

результат её выполнения:

constructor
constructor

constructor
destructor
destructor // !!!!!!

destructor
destructor

ivank
09-02-2007, 04:32
zl3p
Предлагаю вам ознакомиться с таким понятием, как "конструктор копирования по умолчанию".

vector vector::operator + (const vector &obj)
{
if (this->n != obj.n) cout << "Error: diff. dim\n";
vector tmp(obj.n);
for (long i=0; i<obj.n; i++) {
tmp.x[i] = this->x[i] + obj.x[i];
}
return tmp; // (1)
}
void main()
{
{
vector a(3);
vector b(3);
a + b; // (2)
}
getch();
}


В строчке (1) происходят следующие действия: создаётся копия объекта tmp на стеке (используя конструктор копирования, который вы не объявили, но компилятор создал его самостоятельно), объект tmp был уничтожен (с вызовом деструктора, в первый раз). Затем в строке (2) временный объект используется (в данном случае никак не используется) и удаляется (второй вызов деструктора).

В общем решение простое - объявите конструктор копирования, например так
vector::vector (const vector &v)
{
n = v.n;
x = new real[n];
*this = v;
cout << "constructor \n";
}

Кстати, по стандарту создание временного объекта можно опускать. Поэтому один компилятор (gcc4) даже по вашему первоначальному коду генерирует корректную программу (т.к. не создаёт временный объект и тем самым опускает одну пару конструктор/деструктор), а другой (VS2005 в отладочной конфигурации) - нет.

zl3p
09-02-2007, 17:41
Да! Большое спасибо. Наконец-то я понял для чего нужны эти конструкторы копирования. =)

zl3p
10-02-2007, 22:12
Правда, всё оказалось не так просто....
С ростом размера проги, начали возникать разные глюки. Теперь уже даже не знаю, где искать ошибки.
В частности, ещё не до конца понял как работает простая строка
*this = v;
в конструкторе копирования. Здесь вызывается перезагруженный оператор "=" или происходит побитное копирование?

Кстати, чего лучше такого почитать по ООП, где всё это, и не только, было бы доступно объяснено?

ivank
10-02-2007, 22:52
в конструкторе копирования. Здесь вызывается перезагруженный оператор "=" или происходит побитное копирование?Перегруженный оператор. Мне лень было писать цикл для копирования второй раз.

Кстати, чего лучше такого почитать по ООП, где всё это, и не только, было бы доступно объяснено?Эти вопросы к ООП отношения не имеют по большому счёту. Они имеют отношение к реализации принципов этого подхода в конкрутном языке (C++). Соответственно любая приличная книга по плюсам даст на них ответы. Шестой год всем рекомендую Страуструпа. На самом деле, очень доходчиво и просто (может, и не совсем на новичков, но специальных знаний и опыта не трубет).




© OSzone.net 2001-2012