Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   От куда взялся деструктор? (http://forum.oszone.net/showthread.php?t=79031)

zl3p 09-02-2007 03:04 547634

От куда взялся деструктор?
 
Решение этой проблемы меня уже порядком достало, поэтому решил спросить у профессионалов, знающих ООП.

Проблема собтвенно в том, что в следующем перезагруженном операторе выполняется 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 547642

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 547867

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

zl3p 10-02-2007 22:12 548294

Правда, всё оказалось не так просто....
С ростом размера проги, начали возникать разные глюки. Теперь уже даже не знаю, где искать ошибки.
В частности, ещё не до конца понял как работает простая строка
Цитата:

*this = v;
в конструкторе копирования. Здесь вызывается перезагруженный оператор "=" или происходит побитное копирование?

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

ivank 10-02-2007 22:52 548307

Цитата:

в конструкторе копирования. Здесь вызывается перезагруженный оператор "=" или происходит побитное копирование?
Перегруженный оператор. Мне лень было писать цикл для копирования второй раз.

Цитата:

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


Время: 03:23.

Время: 03:23.
© OSzone.net 2001-