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

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Serge
Сообщения: 14
Зарегистрирован: 13 апр 2005, 14:43
Откуда: Украина, Кривой Рог

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();
}
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Вообще-то выражение

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

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

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

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

Можно создавать объекты abObject в куче с помощью new, и хранить в векторе указатели, но это тоже хлопотно.
2B OR NOT(2B) = FF
Serge
Сообщения: 14
Зарегистрирован: 13 апр 2005, 14:43
Откуда: Украина, Кривой Рог

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

изменил конструктор копирования:
abObject(const abObject &o){id=o.id;bActive=o.bActive;data=NULL;}
теперь работает.
Спасибо за подсказку!
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Всё победимо, Absurd, если постараться :) Serge, один вопрос. Нигде не вижу где полю data присваивается что-либо отличное от NULL? Более того, это поле приватное, так что снаружи его тоже не выставить. Зачем вообще поле data нужно. Если ты сможешь ответить на этот вопрос, то, наверняка, сможешь разрешишь возникшую проблему и без нашей помощи.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Serge
Сообщения: 14
Зарегистрирован: 13 апр 2005, 14:43
Откуда: Украина, Кривой Рог

Это просто шаблон для программы. В реальной там будет храниться указатель на массив данных. Пока еще не знаю какой.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

В реальной там будет храниться указатель на массив данных. Пока еще не знаю какой
Возьми из shared_ptr из буста (http://www.boost.org)
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Либо, если не хочешь писать отдельный класс-смартпоинтер, то в конструкторе копирования твоего класса, нужно копировать соответствующий массив, а не просто переприсваивать ссылку. Отмечу, что смартпоинтер, не важно из инета ты его возьмёшь, или сам напишешь, куда более приемлемое решение.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Отмечу, что смартпоинтер, не важно из инета ты его возьмёшь, или сам напишешь, куда более приемлемое решение.
Я бы не посоветовал писать свой смарт-поинтер. Это очень сложно даже для профессионала.
2B OR NOT(2B) = FF
Ответить