LINUX.ORG.RU

С++ поведение деструктора?

 


0

3

Здравствуйте. Возник вопрос надеюсь вы сможете помочь. Деструктор по умолчанию в С++ вызывает деструкторы всех членов данных объявленных в классе. Если я определю деструктор например:

class A{
  std::vector<MyClass> V_;
  int num_;
public:
  A(){};
  ~A(){
    std::cout<<"Hello, World\n";
  }
}
при вызове деструктора объекта класса А будут вызваны детструкторы V_ и num_? Заранее благодарю.



Последнее исправление: mgalimullin (всего исправлений: 3)

при вызове деструктора объекта класса А будут вызваны детструкторы V_ и num_?

Разумеется.

mix_mix ★★★★★
()
Ответ на: комментарий от mgalimullin

Про примитивный тип уже заметили, ещё скажу, что деструкторы вызываются в порядке, обратном порядку объявления полей.

devsdc ★★
()

статичные объектные переменные - да.
динамические - нет, вызываешь сам в деструкторе.

Atlant ★★★★★
()

при вызове деструктора объекта класса А будут вызваны детструкторы V_ и num_? Заранее благодарю.

да.

Однако.

Предположим есть такой код:

#include <iostream>


using namespace std;

class Foo
{
	public:
		Foo()
		{
			cout << "Foo::Foo()\n";
		}
		~Foo()
		{
			cout << "Foo::~Foo()\n";
		}
};

class Bar : public Foo
{
	public:
		Bar()
		{
			cout << "Bar::Bar()\n";
		}
		~Bar()
		{
			cout << "Bar::~Bar()\n";
		}
};

int main()
{
	Foo* b = new Bar;
	delete b;
	return 0;
}

Если его запустить, увидим:

Foo::Foo()
Bar::Bar()
Foo::~Foo()

Деструктор Bar::~Bar() НЕ вызывается.

Откуда правило: Деструктор ВСЕГДА должен быть виртуальным

emulek
()
Ответ на: комментарий от emulek

Откуда правило: Деструктор ВСЕГДА должен быть виртуальным

Плохое правило. Если объект не предполагает наследования, то зачем создавать для него vtbl?

andreyu ★★★★★
()
Ответ на: комментарий от stevejobs

сколько на этом можно сэкономить?

От задачи зависит. Некоторые и new / delete внутри цикла вызывают и это им не мешает. А некоторые забор на морозе лижут, говорят он сладкий.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Плохое правило. Если объект не предполагает наследования

а как ты это проконтролируешь? С дубиной будешь бегать?

зачем создавать для него vtbl?

что-бы не было утечек памяти и прочей «радости» от того, что твой деструктор НЕ сработал.

Оно жеж ведь как бывает:

1. вася пишет класс, которые не предполагает наследования.

2. петя пишет коллекцию, которая содержит объекты васиного класса.

3. OH SHI~~

emulek
()
Ответ на: комментарий от stevejobs

сколько на этом можно сэкономить?

sizeof(void*) на каждый объект класса. Это если _действительно_ VT не нужна. Хотя открытым остаётся вопрос: если вам не нужна VT, то почему вы пишите на C++, а не на ansi C ?

emulek
()
Ответ на: комментарий от emulek

а как ты это проконтролируешь? С дубиной будешь бегать?

А зачем мне это контролировать? Контроль должен лежать на том, кто решится на наследование, когда оно не предполагается.

что-бы не было утечек памяти и прочей «радости» от того, что твой деструктор НЕ сработал.

В плюсах и без этого можно наделать кучу мемори-ликов. При чем тут наследование?

Оно жеж ведь как бывает:

Ну так с дуру можно много чего сломать.

andreyu ★★★★★
()
Ответ на: комментарий от emulek

а как ты это проконтролируешь? С дубиной будешь бегать?

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

А в новом, точнее еще в C++11, стандарте появилось словечко final.

BRE ★★
()
Ответ на: комментарий от emulek

sizeof(void*) на каждый объект класса.

Если бы.
Кроме этого есть накладные расходы на вызов виртуального метода.

Хотя открытым остаётся вопрос: если вам не нужна VT, то почему вы пишите на C++, а не на ansi C ?

Ну так пораскиньте мозгом, может сообразите.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

А зачем мне это контролировать? Контроль должен лежать на том, кто решится на наследование, когда оно не предполагается.

Т.е. ты решаешь, что эти объекты нельзя объединять в коллекции? Ну и нафиг нужны такие объекты?

В плюсах и без этого можно наделать кучу мемори-ликов

хорошее оправдание говнокода.

Ну так с дуру можно много чего сломать.

дык зачем пихать пипиську в непонятные и не предназначенные для этого отверстия? Не делай так, и всё будет хорошо.

emulek
()
Ответ на: комментарий от emulek

Т.е. ты решаешь, что эти объекты нельзя объединять в коллекции? Ну и нафиг нужны такие объекты?

Причем здесь коллекции этих объектов и зачем им виртуальные деструкторы?

BRE ★★
()
Ответ на: комментарий от BRE

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

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

А в новом, точнее еще в C++11, стандарте появилось словечко final.

ну дык и используй его. Если уж так необходимо выиграть sizeof(void*) памяти.

Но, ИМХО, игра не стоит свеч.

emulek
()
Ответ на: комментарий от emulek

виртуальные функции вообще говоря не обязательны для наследования.

Еще раз. Если у класса не будет виртуальных методов, то и смысла в наследовании и доступе к объектам через базовый класс не будет.

BRE ★★
()
Ответ на: комментарий от andreyu

Кроме этого есть накладные расходы на вызов виртуального метода.

это копейки. И нужно ОЧЕНЬ хорошо подумать, прежде чем делать такую преждевременную оптимизацию.

Ну так пораскиньте мозгом, может сообразите.

не осилили ASCIIZ строки, и потому юзаете std::string?

emulek
()
Ответ на: комментарий от emulek

Деструктор ВСЕГДА должен быть виртуальным

Бить за такое ссаными тряпками.

Даже при возможном наследовании деструктор может не быть виртуальным. Он может быть защищенным, например.

В структурах ты тоже всегда виртуальный деструктор лепишь?

anonymous
()
Ответ на: комментарий от BRE

Причем здесь коллекции этих объектов и зачем им виртуальные деструкторы?

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

Но для того, что-бы коллекция могла удалить OE, деструктор OE::~OE() должен быть виртуальным. В силу того, что коллекция ничего не знает про OE, а знает лишь про E.

Заметь, что я ничего не говорил о наследовании от OE, OE вполне может быть final, и тем не менее, OE::~OE() должен быть виртуальным.

emulek
()
Ответ на: комментарий от ranka-lee

Если от класса наследоваться не надо то и деструктор делать виртуальным не надо.

проблема невиртуального деструктора проявляется не тогда, когда от него наследуют, а когда его самого наследуют.

Не, конечно можно сделать комментарий, и всё такое. И выиграть sizeof(void*) и пару тактов. Удачи.

emulek
()
Ответ на: комментарий от anonymous

Бить за такое ссаными тряпками.

убейся.

Даже при возможном наследовании деструктор может не быть виртуальным. Он может быть защищенным, например.

давай вообще без деструктора?

В структурах ты тоже всегда виртуальный деструктор лепишь?

структуры у меня всегда POD.

emulek
()
Ответ на: комментарий от emulek

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

Третий раз пишу. Подумай, для чего наследоваться от класса у которого нет виртуальных методов и использовать указатель на него, для доступа к дочерним классам. :))))

BRE ★★
()
Ответ на: комментарий от emulek

Люди что писали на приставках прошлого поколения за виртуальные деструкторы без очень хорошей причины били силикатным кирпичом по голове до наступления полного просветления.

ranka-lee
()
Ответ на: комментарий от ranka-lee

саму vtbl

сама VT всего одна на весь код.

плюс цену косвенного вызова.

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

emulek
()
Ответ на: комментарий от emulek

а когда его самого наследуют.

Поэтому тебе написали про protected. А вообще проблема появляется не когда его наследуют, а когда его удаляют через указатель базового класса. И про структуры ты так и не ответил. В каждую структуру суешь виртуальный деструктор? и если нет, то почему, чем отличается struct от class в C++, кроме дефолтной видимости?

anonymous
()
Ответ на: комментарий от emulek

Косвенные вызовы очень дорогие. Считай сам.

1. Надо прочитать vtbl. Если её нет в кэше (а скорее всего её нет) - привет 200+ тактов.

2. Надо прочитать код по указателю. Привет ещё 200+

3. Надо подождать пока процессор декодирует инструкции и начнёт их исполнять.

4. Потом надо вернуться назад, что снова остановка процессорного конвейера. И это если код из кэша ещё не улетел.

ranka-lee
()
Последнее исправление: ranka-lee (всего исправлений: 1)
Ответ на: комментарий от BRE

Подумай, для чего наследоваться от класса у которого нет виртуальных методов и использовать указатель на него, для доступа к дочерним классам.

говорю в третий раз: к примеру для коллекций. С доступом к примеру по порядковому номеру. Вот зачем коллекции дёргать виртуальные методы? Кроме деструктора конечно.

emulek
()
Ответ на: комментарий от emulek

Один конкретный случай не оправдывает подобное. Если ты не делаешь ContainerForFoo : public Foo то зачем оно? Для некого гипотетического случая которого с вероятностью 99.9999% никогда не случиться?

ranka-lee
()
Ответ на: комментарий от emulek

Зачем в коллекциях использовать указатель на базовый класс и хранить объекты классов-наследников, если у базового класса нет виртуальных методов? В чем смысл? :)

BRE ★★
()
Ответ на: комментарий от metawishmaster

Тогда нет, ибо в java нет деструкторов и что и когда будет удалено, в общем случае, неизвестно. Один из немногих минусов сборки мусора.

anonymous
()
Ответ на: комментарий от ranka-lee

Люди что писали на приставках прошлого поколения

За кой ляд они вообще на C++ писали?

Что-то ты странное говоришь: с одной стороны плачешь о копеечных ресурсах, которые теряются на VT, с другой почему-то упрямо юзаешь C++.

А в C++ всегда так: даже реализация простых списков на шаблонах тоже не настолько оптимальна, как реализация на чистой сишке. За абстракции всегда нужно платить.

emulek
()
Ответ на: комментарий от ranka-lee

Там не пара тактов, там легко может быть в районе 1000 и выше.

пара delete в деструкторе съедят больше. Намного больше.

emulek
()
Ответ на: комментарий от anonymous

Поэтому тебе написали про protected.

костыль.

А вообще проблема появляется не когда его наследуют, а когда его удаляют через указатель базового класса.

именно так.

И про структуры ты так и не ответил.

ответил. В моих структурах нет методов. Вообще.

и если нет, то почему, чем отличается struct от class в C++, кроме дефолтной видимости?

ничем.

emulek
()
Ответ на: комментарий от emulek

Потому, что си - говно мамонта. Ни шаблонов, ни дженериков(вернее есть _Generic в C11, но он не о том), ни пространств имён, ни банальной перегрузки функций, ни лямбд. Постоянная возня с указателями и байтиками, которую ничем нельзя прикрыть и от которой не скроешься ни за какими абстракциями. Просто из-за убогости языковых средств. Одно говно. C++ тоже ужасен, но на нем хотя бы теоретически можно писать нормальный код. На си это практически невозможно. Ждем, когда от них обоих можно будет отказаться. От си можно отказаться уже сейчас в большинстве случаев.

anonymous
()
Ответ на: комментарий от ranka-lee

Для некого гипотетического случая которого с вероятностью 99.9999% никогда не случиться?

откуда цифры? Провел статистическое исследование?

emulek
()
Ответ на: комментарий от BRE

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

зачем вообще придумали списки, массивы, хеши?

emulek
()
Ответ на: комментарий от emulek

Деструктор ВСЕГДА должен быть виртуальным

А тебя не смущает, что в стандартной библиотеке у многих классов деструкторы не виртуальные? И это не из-за того, что авторы стандарта тупые и не знают, что такое утечки памяти.

Gvidon ★★★★
()
Ответ на: комментарий от anonymous

Потому, что си - говно мамонта. Ни шаблонов, ни дженериков(вернее есть _Generic в C11, но он не о том), ни пространств имён, ни банальной перегрузки функций, ни лямбд.

за то там есть указатели, которые ты не осилил.

От си можно отказаться уже сейчас в большинстве случаев.

скажи это Линусу.

emulek
()
Ответ на: комментарий от Gvidon

А тебя не смущает, что в стандартной библиотеке у многих классов деструкторы не виртуальные?

это ты про STL? Там полиморфизм достигается другим путём, на то это и шаблоны.

emulek
()
Ответ на: комментарий от emulek

От си можно отказаться уже сейчас в большинстве случаев.

скажи это Линусу.

А этот Линус написал большинство ПО? Вот ты валенок. :-)

i-rinat ★★★★★
()
Ответ на: комментарий от emulek

это ты про STL? Там полиморфизм достигается другим путём, на то это и шаблоны.

vector<int> и vector<double> это разные типы. Ну нет тут полиморфизма. Вот ты валенок. :-)

i-rinat ★★★★★
()
Ответ на: комментарий от emulek

а как ты это проконтролируешь? С дубиной будешь бегать?

final

m0rph ★★★★★
()
Ответ на: комментарий от emulek

В моих структурах нет методов. Вообще.

Если тебе не нужно держать объекты в структурах, зачем тебе тогда вообще C++? На форумах умничать?

i-rinat ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.