Простая программа, но есть вопрос

15.10.2005
14
0
#1
Код:
#include <map>

// ---------------------базовый класс - распределения
class ZRV
{
public:
virtual ~ZRV() {}

virtual const char*PoluchitNaim()=0;
};

// ---------------------- нормальное распределение --------------
class NormalZRV:public ZRV
{
public:
// s - среднее, sig - станд.откл.
NormalZRV(double s, double sig) : s(s), sig(sig),s1("среднее"),sig1("станд.откл."){}
virtual ~NormalZRV() {}


const char*PoluchitNaim() { return "нормальное";}

private:
double s,sig;
char *s1,*sig1;
};

//-----------------------"умный указатель"-------------------
class PtrZRV
{
public:
PtrZRV() {;}

template<class T> PtrZRV(T& ref) :ptr(new T(ref)) {}
~PtrZRV()					  
{ 
delete ptr;
} 
private:
ZRV* const ptr;
};

void main(void)
{
typedef std::multimap<int, PtrZRV> ut;
ut a;
NormalZRV nzrv(1.0, 0.0);
a.insert(ut::value_type(1,nzrv));
}

Идея проста: есть базовый класс (распределения), на нем построен класс NormalZRV (нормальное распределение). Для базового класса ZRV создан класс "умный указатель".
Класс "умный указатель" используется в STL multimap.
Подскажите, почему после вызова метода insert для одного и того же экземпляра класса PtrZRV деструктор вызывается дважды?
 
6

62316e

#2
Чесно это ты писал?
В СТЛ есть такие приколы. Обекти чясто создаютса и удаляютса.
Кароче определи к-тор копирования и обнуляй в нем старый указатель.
 
15.10.2005
14
0
#3
Чесно это ты писал?
В СТЛ есть такие приколы. Обекти чясто создаютса и удаляютса.
Кароче определи к-тор копирования и обнуляй в нем старый указатель.
Конечно.
Думал над конструктором копирования . Но как он будет выглядеть для PtrZRV? Чтобы компилировалось без ошибок.
 
J

jo1nt

#4
Я так понимаю, тут создается еще 1 копия:
PtrZRV(T& ref) :ptr(new T(ref))
//T(ref) вызывает конструктор копии, со старым объектом ничего не происходит!
соответсвенно,
//-1 объект
a.insert(ut::value_type(1,nzrv));
// 1+1 =2 объекта.
При выходе из области видимости вызывается деструктор для 2 объектов, чего и следует ожидать( 1 раз для NormalZRV второй для PtrZRV (который вызывает деструктор NormalZRV) .

Шаблон auto_ptr(из mem) реализует деструктивное копирование, то есть уничтожает объект, УКАЗАТЕЛЬ(НЕ ССЫЛКА!!!) на который передается ему в конструкторе. Я бы рекомендовал использовать его (и обращаться к нему проще, и необходимые функции в нем уже написаны).
 
6

62316e

#5
Кста, michael_is_98 ты чем компилил?
А вот что поидеи получилось...
Код:
#include <map>
class ZRV
{
public:
virtual ~ZRV() {}
virtual const char*PoluchitNaim()=0;
};
class NormalZRV:public ZRV
{
public:
NormalZRV(double s, double sig) : s(s), sig(sig),s1("среднее"),sig1("станд.откл."){}
virtual ~NormalZRV() {}
const char*PoluchitNaim() { return "нормальное";}
private:
double s,sig;
char *s1,*sig1;
};
class PtrZRV
{
public:
PtrZRV(const PtrZRV &cpy): ptr()
{
//static int i = 0;
//i++; // i == 2
}
template<class T> PtrZRV(T& ref) :ptr(new T(ref)) {}
~PtrZRV()					 
{
//if (ptr)
delete ptr;
}
private:
ZRV* const ptr;
};

typedef std::multimap<int, PtrZRV> ut;

void main(void)
{
ut a;
NormalZRV nzrv(1.0, 0.0);
a.insert(ut::value_type(1,nzrv));
}
 
15.10.2005
14
0
#6
Разобрался...
Компилировал на VC 5.0... Что-то на нем не получалось сделать из того, что получилось в VC7.0.
Видимо есть недостатки. И STL несколько староват.
Да, auto_ptr лучше... Это и есть "умный указатель"? С его помощью программа идет (но несколько доработал ее). И теперь многие законы распределения вер-тей можно вписать в новую схему...
Спасибо за помощь!
 
15.10.2005
14
0
#7
Разобрался...
Компилировал на VC 5.0... Что-то на нем не получалось сделать из того, что получилось в VC7.0.
Видимо есть недостатки. И STL несколько староват.
Да, auto_ptr лучше... Это и есть "умный указатель"? С его помощью программа идет (но несколько доработал ее). И теперь многие законы распределения вер-тей можно вписать в новую схему...
Спасибо за помощь!
Все-таки вопросы появились. Убрал свой класс "умного указателя" и использовал auto_ptr. Т.е.

#include <memory>
typedef std::auto_ptr<ZRV> pZRV;

Попытался использовать ассоциативный контейнер map

void main(void)
{
typedef std::multimap<int, pZRV> ut;
ut a;
a.insert(ut::value_type(1,pZRV(new NormalZRV(.0,.0)) ));
}

Компилятор выдает ошибку - нет конструктора копирования у pZRV.
Неужели нельзя использовать класс pZRV в map?
 
J

jo1nt

#8
Попробуй так:
Код:
typedef std::multimap<int, ZRV> ut;
typedef std::auto_ptr<ZRV> pZRV;
ut a;
a.insert(ut::value_type(1,(pZRV(new NormalZRV(.0,.0))).get()));
// то есть :
//pZRV p1(new ZRV(.0,.0));
//ZRV p2=p1.get();
//a.insert(ut::value_type(1,p2));

Вообще, использование auto_ptr в стандартных контейнерах рисковано, поскольку оператор "=" работает нестандартно(уничтожает rsh). Алгоритмы, модифицирующие последовательность (напр. sort)
скорей всего испортят эту последовательность.
 
15.10.2005
14
0
#9
Попробуй так:
Код:
typedef std::multimap<int, ZRV> ut;
typedef std::auto_ptr<ZRV> pZRV;
ut a;
a.insert(ut::value_type(1,(pZRV(new NormalZRV(.0,.0))).get()));
// то есть :
//pZRV p1(new ZRV(.0,.0));
//ZRV p2=p1.get();
//a.insert(ut::value_type(1,p2));
Вообще, использование auto_ptr в стандартных контейнерах рисковано, поскольку оператор "=" работает нестандартно(уничтожает rsh). Алгоритмы, модифицирующие последовательность (напр. sort)
скорей всего испортят эту последовательность.
Понятно, а как тогда лучше создать ассоциативный контейнер, который будет содержать структуры различных типов с различными полями. Не создавать же контейнер под каждую конкретную структуру?
С помощью указателей это еще возможно - путем приведения (настройки) указателя на опред. тип.
Что такое rsh?
 
J

jo1nt

#10
rsh, вернее rhs(опечатка вышла) - Right Hand Side, то что справа от оператора присваивания, напр. :
Код:
int a=10; //a -lhs, 10 -rhs