Страница 1 из 1

Проблема с std::vector(STL)

Добавлено: 13 апр 2005, 15:04
Serge
Borland C++ v5.02
при выполнении программы (перед завершением)
выдает Fault: acces violation at 0x43408a
ead of address x20a0003f
сразу подозрение падает на деструкторы, но понять не могу...

Код: Выделить всё

#include <vector>
#include <iostream.h>
#include <iomanip.h>
#include <constrea.h>
using namespace std;
class abObject
{
 private:
 	unsigned short id;
   int bActive;
   void * data;
 public:
 	abObject();
   abObject(const abObject &o){id=o.id;bActive=o.bActive;}
   abObject(unsigned short i){id=i;bActive=1;}
   ~abObject();
   void activate(){bActive=1;}
   void setId(unsigned short i){id=i;bActive=1;}
   friend ostream& operator << (ostream& ,abObject&);
   friend istream& operator >> (istream& ,abObject&);
};

ostream& operator << (ostream& os,abObject & o)
{
	if(o.bActive)os<<"Object id:"<<o.id<<endl;
   else os<<"Object is disabled"<<endl;
   return os;
}

istream& operator >>(istream& is, abObject& o)
{
  is>>o.id;
  o.bActive=1;
  return is;
}

abObject::abObject()
{
	bActive=0;
   data=NULL;
}

abObject::~abObject()
{
	if(data) delete data;
}
void main()
{
	vector <abObject> vo ;
   int i;
   clrscr();
   abObject a1(11),a2(22),a3(33);
   vo.push_back(a1);
   vo.push_back(a2);
   vo.push_back(a3);
   cout<<"size:"<<vo.size()<<endl;
   for(i=0;i<vo.size();i++) cout<<vo[i];
   cout<<endl;
   cin.get();
}

Добавлено: 13 апр 2005, 15:37
Absurd
Вообще-то выражение

Код: Выделить всё

if(data) delete data; 
излишне. В соответствии со стандартом delete под нулевой указатель допустимо, и ничего не делает.
А то, что не излишне - так это то, что если указатели data будут указывать не на null, то деструкторы 100% порушат программу.

При помещении в вектор создается копия объекта, и следовательно память будет освобождаться два раза - в первый раз самим объектом, а во второй раз его копией из вектора. Делать delete два раза под один адрес категорически нельзя.

Легкого выхода из этои ситуации нет;
Помог бы смарт-указатель с подсчетом ссылок, но его нет в стандартной библиотеке. std::auto_ptr не подойдет - он не считает ссылки.

Можно создавать объекты abObject в куче с помощью new, и хранить в векторе указатели, но это тоже хлопотно.

Добавлено: 13 апр 2005, 16:02
Serge
Да, проблема в этом. Но ведь delete вызывается если было выделение памяти. В данном случае почему он вызывается?
А может это из-за неправильного конструктора копирования? Действительно объект будет создан с неустановленым в NULL указателем data. Соответственно выполнится и delete.

Добавлено: 13 апр 2005, 16:04
Serge
изменил конструктор копирования:
abObject(const abObject &o){id=o.id;bActive=o.bActive;data=NULL;}
теперь работает.
Спасибо за подсказку!

Добавлено: 13 апр 2005, 16:05
Romeo
Всё победимо, Absurd, если постараться :) Serge, один вопрос. Нигде не вижу где полю data присваивается что-либо отличное от NULL? Более того, это поле приватное, так что снаружи его тоже не выставить. Зачем вообще поле data нужно. Если ты сможешь ответить на этот вопрос, то, наверняка, сможешь разрешишь возникшую проблему и без нашей помощи.

Добавлено: 14 апр 2005, 12:07
Serge
Это просто шаблон для программы. В реальной там будет храниться указатель на массив данных. Пока еще не знаю какой.

Добавлено: 14 апр 2005, 15:19
Absurd
В реальной там будет храниться указатель на массив данных. Пока еще не знаю какой
Возьми из shared_ptr из буста (http://www.boost.org)

Добавлено: 14 апр 2005, 15:41
Romeo
Либо, если не хочешь писать отдельный класс-смартпоинтер, то в конструкторе копирования твоего класса, нужно копировать соответствующий массив, а не просто переприсваивать ссылку. Отмечу, что смартпоинтер, не важно из инета ты его возьмёшь, или сам напишешь, куда более приемлемое решение.

Добавлено: 14 апр 2005, 16:02
Absurd
Отмечу, что смартпоинтер, не важно из инета ты его возьмёшь, или сам напишешь, куда более приемлемое решение.
Я бы не посоветовал писать свой смарт-поинтер. Это очень сложно даже для профессионала.