Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Вызывается ли деструктор?


Автор: Riddik 6.5.2009, 00:29
Вопрос, скорее всего, дурацкий, но мне для успокоения smile

Есть два классы, пусть Monstr и Male, в их конструкторе выделяется память, в деструкторе - освобождается.

Эти классы помещаются в контейнер типа вектор, содержащий указатель на базовый класс, из которого выведены Monstr и Male:

Код

std::vector<base*> pbase;
pbase.push_back(new Monstr());
pbase.push_back(new Male());
 

Затем, когда возникает необходимость, контейнер очищается :
Код

pbase.clear();


Вопрос: когда очищается контейнер таким способом, вызывается ли деструктор класса Monstr и деструктор класса Male? Другими словами, та память, что выделяется их конструкторами, освобождается? Или для успокоения написать отдельную функцию, которая будет это делать и вызывать её вместе с очисткой контейнера?

Автор: mes 6.5.2009, 00:31
Вызов деструктора наследника, будет произведен, только если он помечен виртуальным в базовом.
Вектор указателей, при очищении не удаляет объекты. Это Вы должны сделать самостоятельно.

исправлено


Автор: Riddik 6.5.2009, 00:33
mes, не понял, простите. Если сделать виртуальный деструктор в базовом?

Автор: mes 6.5.2009, 00:36
Цитата(Riddik @  5.5.2009,  23:33 Найти цитируемый пост)
Если сделать виртуальный деструктор в базовом? 

да. (в наследниках он автоматическки получится тоже виртуальный.)

Автор: Riddik 6.5.2009, 00:41
Как же его объявить, возникают ошибки, не хочет компилироваться:
Код

class base
{
public:
  virtual ~base();



или 
Код

virtual ~base()=0;



?

Автор: mes 6.5.2009, 00:45
Цитата(Riddik @  5.5.2009,  23:41 Найти цитируемый пост)
Как же его объявить, возникают ошибки, не хочет компилироваться:

Вы ошибки то читаете ? там же ясным языком написано, что нет определения у функции. Или Вы на ощупь программируете ?  smile 
Код

 virtual ~base() {}


Автор: Riddik 6.5.2009, 00:46
И ещё такой момент, есть просто указать на базовый класс, которому выделяется память на производный из него:
Код

base *p=new Monstr();


Затем память удаляется: delete p; 
Естественно, деструктор класса Monstr вызван не будет? То же самое, что с pbase.clear() ?

Добавлено через 2 минуты и 56 секунд
mes, на ощупь, конечно.  smile 
Я, если честно, про такие инструкции  virtual ~base() {} ничего не знаю ещё.

Спасибо  smile

Добавлено через 4 минуты и 13 секунд
Это так же вызовет деструктор classA и при p=new classA;  delete p; ?

Автор: mes 6.5.2009, 00:56
Цитата(Riddik @  5.5.2009,  23:46 Найти цитируемый пост)
на ощупь, конечно.  smile 
Я, если честно, про такие инструкции  virtual ~base() {} ничего не знаю ещё.

а также то что у вызываемой  функции должно быть тело. А самое главное, что, к сожалению, даже не попытались обдумать сообщение компилятора.
ибо сегодня в соседней теме Вам уже сообщали о решении подобной проблемы.

Цитата(Riddik @  5.5.2009,  23:46 Найти цитируемый пост)
И ещё такой момент, есть просто указать на базовый класс, которому выделяется память на производный из него:

Нет. Есть указатель, котоорый инизиализируется адресом новосозданного объекта.

Цитата(Riddik @  5.5.2009,  23:46 Найти цитируемый пост)
Затем память удаляется: delete p; 
Естественно, деструктор класса Monstr вызван не будет?

при delete автоматически вызывается деструктор. Если он был объявлен как виртуальный, то вызовется и для наследникa (Monstr)

Цитата(Riddik @  5.5.2009,  23:46 Найти цитируемый пост)
То же самое, что с pbase.clear() ?

нет, не то же самое. В delete "скрыт" вызов деструктора, а clear () - обычная функция.

Автор: Riddik 6.5.2009, 00:59
У функции должно быть тело, а как же чисто виртуальные ф-ии

virtual void func()=0;

почему не virtual void func() {}

Добавлено @ 01:10
 smile 
поискал в соседней теме - не нашёл, где мне сообщили о решении подобной проблеме, речь шла об абстрактном классе, а проблема была в том, что его наследники получились тоже абстрактными. Про деструкторы и {} там мне ничего не говорили.

Автор: J0ker 6.5.2009, 01:10
Riddik, у вас в голове каша
учите матчасть

Автор: Riddik 6.5.2009, 01:11
J0ker,  Да учу я, но и бегу вперёд поезда

Добавлено через 1 минуту и 46 секунд
:(

Автор: J0ker 6.5.2009, 01:17
уясните для начала разницу между pure virtual, virtual и abstract

Автор: Riddik 6.5.2009, 01:22
pure virtual, virtual и abstract 
вы будете смеятся, но в тех книжках, которые я уже прочёл, об этом ни слова smile

Добавлено через 21 секунду
вернее только про virtual

Автор: J0ker 6.5.2009, 01:24
значит вы читали что-то не по С++

Автор: mes 6.5.2009, 01:26
Цитата(Riddik @  5.5.2009,  23:59 Найти цитируемый пост)
У функции должно быть тело, а как же чисто виртуальные ф-ии

Цитата(mes @  5.5.2009,  23:56 Найти цитируемый пост)
У вызываемой  функции должно быть тело

я специально сделал акцент на слово вызываемая. У виртуальных функций, тело связывается с вызовом в рантайме (в отличие от обычных - на этапе линковки).
И чтоб не было возможности вызвать функцию, у которой нет связи с телом, нельзя создавать объекты абстрактных классов.
Да фраза не совсем корректная, но она намекала на возможный ход мыслей, когда бы Вы прочитали ошибку компилятора.
Там написано : не хватает тела функции. Следовательно Вы должны были подумать как объяснить компилятору, где искать.
или написать тело или пометить чисто-виртуальной (ну или и то другое, но Вам это рано)

P.S У деструктора, тело  должно быть всегда, даже когда он помечен, как чистая виртуальная функция.
У виртуальных функций, тело может быть не определено, но должнa быть метка "чистоты" .
Если у класса есть хоть одна функция, помеченная как "чистая", то объект такого класса нельзя создать.



Автор: Riddik 6.5.2009, 01:26
Купник. Изучаем С++
Франка. Самоучитель С++
Шилдт. Базовый курс С++

Добавлено через 1 минуту и 41 секунду
mes, спасибо большоеsmile

Автор: mes 6.5.2009, 01:29
Цитата(Riddik @  5.5.2009,  23:59 Найти цитируемый пост)
почему не virtual void func() {} 

так тоже можно, 
чистые функции объявляются для того, если хотите использовать указатель на базовый класс как интерфейс,
и объект подобного типа Вам не нужен. 

Автор: Riddik 6.5.2009, 01:35
mes, ещё раз спасибо за объяснения! 
Значит в любом случае у деструктора должно быть тело ф-ии, даже если это чисто-виртуальный деструктор в абстрактном классе. smile




P.S. Понимаю, что опытных программистов должно бы быть раздражает, когда говорят такие вещи, как  я говорил здесь про память и указатели на неё, вроде "укзатель на базовый класс, ему выделяется память" - на самом деле уж это я понимаю, что выделяется память и адрес этой памяти присваивается указателю, а сказал небрежно, каюсьsmile

Автор: mes 6.5.2009, 01:42
Цитата(Riddik @  6.5.2009,  00:35 Найти цитируемый пост)
Значит в любом случае у деструктора должно быть тело ф-ии, даже если это чисто-виртуальный деструктор в абстрактном классе. smile

Да.

Цитата(Riddik @  6.5.2009,  00:35 Найти цитируемый пост)
на самом деле уж это я понимаю, что выделяется память и адрес этой памяти присваивается указателю, 

Создается объект. А выделение памяти это всего лишь один из этапов создания объекта.  smile 

Автор: Riddik 6.5.2009, 01:52
Не буду умничатьsmile 

Автор: Riddik 6.5.2009, 02:07
с delete всё нормально - вызывается деструктор, в если очищать вектор - не вызывается

Код

#include <iostream>
#include <vector>
using namespace std;

class base
{
public:
    virtual void vivod()=0;
    virtual ~base() {}
};

class A:public base
{
public:
    void vivod() {cout<<"This is class A"<<'\n';}
    ~A(){cout<<"This is destructor A"<<'\n';}
    A() {cout<<"This is constructor A"<<endl;}
};

class B:public base
{
public:
    void vivod() {cout<<"This is class B"<<'\n';}
    ~B() {cout<<"This is destructor B"<<'\n';}
    B() {cout<<"This is constructor B"<<endl;}
};

int main(int argi, char *argc[])
{
    vector<base*> pb;

    for(int i=0; i<5; i++) pb.push_back(new A);
    cout<<endl;
    for(int i=0; i<5; i++) pb.push_back(new B);

    pb.clear();  

    return 0;
}



Результат: выводит по пять строк "This is constructor А" и "This is constructor B", деструктор молчит.

А если base *p=new A; затем delete p, то всё нормально, деструктор A вызывается

Автор: mes 6.5.2009, 02:13
Цитата(Riddik @  6.5.2009,  01:07 Найти цитируемый пост)
если очищать вектор - не вызывается

естественно, В векторе Вы храните указатели, а не объекты. За удаление "реальных" объектов он не отвечает.

Автор: Riddik 6.5.2009, 02:16
Не понял, во втором сообщении Вы же ответили "только если он виртуальный в базовом" на вопрос "когда очищается контейнер таким способом, вызывается ли деструктор класса Monstr"

Сорри, уже поздно, наверное я плохо понимаю

Автор: mes 6.5.2009, 02:26
Цитата(Riddik @  6.5.2009,  01:16 Найти цитируемый пост)
е понял, во втором сообщении Вы же ответили

сорри за невнимательность и за то что ввел в заблуждение, я там ответил только на половину вопроса - исправил. 

Цитата(Riddik @  6.5.2009,  01:16 Найти цитируемый пост)
Сорри, уже поздно, 

Ага, и  на меня тоже сказывается   smile 

Автор: Riddik 6.5.2009, 02:32
Ясноsmile

Вот так нормально самому память освобождать:


Код

vector<base*>::iterator it;
for(it=pb.begin(); it<pb.end(); it++) delete *it;

Автор: mes 6.5.2009, 02:40
да

Автор: Riddik 6.5.2009, 02:42
Тогда вопрос решён - спасибо за всёsmile

Автор: azesmcar 6.5.2009, 08:58
вот так будет универсальнее, напишите функтор
Код

struct delete_object {
    template <typename T>
    void operator()(T* ptr)    {
        delete ptr;
    }
};

вызов
Код

std::for_each(container.begin(), container.end(), delete_object());

будет работать для любого (STL совместимого) контейнера

Автор: Riddik 6.5.2009, 10:03
azesmcar, благодарю.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)