Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/47: Рейтинг темы: голосов - 47, средняя оценка - 4.77
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700

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

18.01.2017, 16:35. Показов 10187. Ответов 111
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вопрос в заголовке темы. Почему? Создается всего 2 объекта, но деструктор вызывается трижды.
Вот пример
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>
 
class Foo
{
    public:
    Foo(int n)
    {
        std::cout << "CONSTRUCT" << std::endl;
    }
    ~Foo()
    {
        std::cout << "DESTRUCTED" << std::endl;
    }
};
 
int main()
{
    std::vector<Foo> v;
    v.reserve(2);
    v.emplace(v.begin(), 1);
    v.emplace(v.begin(), 2);
    std::cout << std::endl << v.capacity() << std::endl;//2
}
http://rextester.com/CFBZ76666

Ещё интересует вот что. Если описать деструктор, нужно ли описывать ещё и деструктор по умолчанию? Если нет, то каким образом происходит освобождение памяти, которое было занято для объекта (речь о простых типах)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.01.2017, 16:35
Ответы с готовыми решениями:

Можно ли обеспечить взаимодействие программно созданных объектов и объектов, созданных мастером
Здравствуйте. Изучаю C# и ADO.NET и столкнулся с одной серьезной проблемой, которая мешает комфортно программировать. Часто...

Почему не срабатывает деструктор и стоимость продуктов не выводится в формате действительного числа?
Добрый вечер. Помогите пожалуйста решить проблему: /*Программа демонстрирует механизм работы конструкторов, деструктора, дружественных...

Почему у двух созданных объектов одинаковые имена
Почему когда я создал 2 объекта и дал им разные имена, в итоге получается что у этих двух объектов одно имя? package helloworld; import...

111
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
18.01.2017, 20:24
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от sys_beginner Посмотреть сообщение
но хогги пишет что этим занимается деструктор по умолчанию
Да, деструктор инициирует процесс по вызову деструкторов и очищению памяти для статических данных. Но это не значит, что пользовательский деструктор не будет этого делать.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 20:26  [ТС]
Croessmah,
Вы так и не ответили на мой вопрос по поводу noexcept

Добавлено через 1 минуту
MrGluck,
Значит происходит невидимое наследование функционала деструктора по умолчанию?)))
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
18.01.2017, 20:39
Цитата Сообщение от sys_beginner Посмотреть сообщение
Значит происходит невидимое наследование функционала деструктора по умолчанию?)))
Ну термин "наследование" тут применять не стоит - он зарезервирован в С++ для других целей, но в общем это так. Даже написанный "руками" деструктор все равно втихаря выполняет ряд неявных действий: он неявно вызывает деструкторы подобъектов данного объекта. (А также в популярых реализациях он обычно опционально вызвает оператор освобождения сырой памяти operator delete). Симметричным образом выглядит и ситуация с конструкторами, так что ничего специфичного именно для деструкторов тут нет.
1
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
18.01.2017, 20:41
Цитата Сообщение от Croessmah Посмотреть сообщение
За тем, что это могут быть не POD-типы.
Это существенно только для добавления/удаления элементов. Для подвижки и реаллокации неусщественно, т.к. внутреннее состояние объекта не зависит от адреса по которому он располагается в памяти.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 20:43  [ТС]
TheCalligrapher,
Т.е говоря про operator delete вы имеете ввиду что деструктор по умолчанию может сам освободить сырую память? Откуда он знает может эта память нам все еще нужна?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
18.01.2017, 20:50
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Для подвижки и реаллокации неусщественно, т.к. внутреннее состояние объекта не зависит от адреса по которому он располагается в памяти.
Здесь речь идет о каком-то конкретном типе?

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

Добавлено через 6 минут
Цитата Сообщение от sys_beginner Посмотреть сообщение
Т.е говоря про operator delete вы имеете ввиду что деструктор по умолчанию может сам освободить сырую память? Откуда он знает может эта память нам все еще нужна?
Освобождение сырой памяти выполнятеся только тогда, когда деструктор вызван непосредственно из delete-выражения. Это известно вызывающему коду о чем он сообщает деструктору через скрытый параметр. Ссылки на "ру.стековерфлоу.ком" тут, я смотрю, запрещены, поэтому просто скопирую свой пост оттуда

---

В языке С++ абстрактный алгоритм работы оператора delete сводится к последовательности из двух шагов:

1. Вызов правильного деструктора объекта
2. Вызов правильной функции освобождения "сырой" памяти operator delete(void *).

Функция operator delete(void *), как известно, может замещаться/перегружаться пользователем. Разрешается как замещать глобальный ::operator delete(void *), так и перегружать статическую функцию operator delete(void *) в конкретных классах. При этом спецификация языка требует, чтобы выбор конкретного operator delete(void *) делался так, как будто его поиск (name lookup) делался из деструктора удаляемого объекта.

Например

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    #include <iostream>
    
    struct B
    {
      virtual ~B()
      { 
        std::cout << "B::~B" << std::endl; 
      }
      
      void operator delete(void *p)
      { 
        std::cout << "B::operator delete" << std::endl;
        ::operator delete(p);
      }
    };
    
    struct D : B
    {
      virtual ~D()
      { 
        std::cout << "D::~D" << std::endl; 
      }
      
      void operator delete(void *p)
      { 
        std::cout << "D::operator delete" << std::endl;
        ::operator delete(p);
      }
    };
    
    int main()
    {
      B* pb = new B;
      B* pd = new D;
      delete pb;
      delete pd;
    }
В таком коде при выполнении delete pb после выполнения деструктора B::~B должен вызваться B::operator delete, а при выполнении delete pd после выполнения деструктора D::~D должен вызваться D::operator delete. Другими словами, несмотря на то, что функция operator delete всегда является статическим членом класса, она должна вести себя фактически как виртуальная (!) функция.

Для того, чтобы удовлетворить этому требованию языка, большинство реализаций просто-напросто переносят вызов правильного operator delete внутрь деструктора. Таким образом требуемая "виртуальность" функции operator delete достигается бесплатно, за счет виртуальности деструктора.

При этом понятно, что operator delete(void *) нужно вызвать только для полных объектов, размещенных в динамической памяти, а для остальных объектов - не нужно (т.е. нельзя). Чтобы принять это во внимание, компиляторы снабжают деструктор неявным булевским параметром, говорящим деструктору, надо ли вызывать operator delete. Таким образом в вышеприведенном примере деструкторы на самом деле будут иметь следующий вид

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      B::~B(bool call_delete)               // неявный параметр
      { 
        std::cout << "B::~B" << std::endl; 
 
        if (call_delete)                    // неявно
          B::operator delete(this);         // неявно
      }
 
      ~D::D(bool call_delete)               // неявный параметр
      { 
        std::cout << "D::~D" << std::endl; 
 
        B::~B(false);                       // неявно
 
        if (call_delete)                    // неявно
          D::operator delete(this);         // неявно
      }
Выражения delete pb и delete pd в такой ситуации превращаются просто в виртуальные вызовы pb->~B(true) и pd->~B(true). Первое попадает в B::~B, второе - в D::~D.

Компилятор GCC, кстати, в более ранних версиях реализовывал этот подход именно так, как описано выше - через скрытый булевский параметр, а в современных версиях этот же поход он реализует через генерацию двух отдельных деструкторов.
4
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 21:07  [ТС]
TheCalligrapher,
Постараюсь разобрать ваш пост, спасибо.
А есть актуальные книжки на русском которые помогут хорошо разбираться в таких деталях?
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 21:10
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
не зависит от адреса по которому он располагается в памяти.
Да ладно? А если объект содержит указатели на свои собственные члены?
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 21:13  [ТС]
TheCalligrapher,
Разобрался)
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.01.2017, 21:22
Цитата Сообщение от sys_beginner Посмотреть сообщение
Если определить собственный деструктор то этот пришибатель т.е деструктор по умолчанию не будет создан, но простые типы тем не менее пришибаются. Как так?
любые типы пришибаются.

компилятор сам автоматом генерит код запуска деструкторов данных-членов.
тобишь, сначала отработает тело явно определенного деструктора.
а затем - код прибивания детишек
1
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
18.01.2017, 21:48
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ссылки на "ру.стековерфлоу.ком" тут, я смотрю, запрещены, поэтому просто скопирую свой пост оттуда
Странно, сколько размещал - ни разу не тёрли.
SO - это же не форум даже, а платформа вопрос-ответ.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 21:54
Цитата Сообщение от MrGluck Посмотреть сообщение
Странно, сколько размещал - ни разу не тёрли.
Англоязычная версия stackoverflow.com разрешена.
Русскоязычная - запрещена.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.01.2017, 21:55
Цитата Сообщение от Croessmah Посмотреть сообщение
Англоязычная версия stackoverflow.com разрешена.
Русскоязычная - запрещена.
шо за дисриминацио?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
18.01.2017, 22:05
Цитата Сообщение от Croessmah Посмотреть сообщение
Англоязычная версия stackoverflow.com разрешена.
Русскоязычная - запрещена.
оО Учитывая, что официальными языками форума являются русский и английский, то какая разница?
Это где-то указано?

Добавлено через 6 минут
Цитата Сообщение от sys_beginner Посмотреть сообщение
А есть актуальные книжки на русском которые помогут хорошо разбираться в таких деталях?
У Майерса вроде бы это было описано. В правилах про перегрузку операторов new/delete.
Впрочем, вы итак всё это поймёте, поэкспериментировав с написанием пользовательского оператора new для класса.
1
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
18.01.2017, 22:16
Цитата Сообщение от Croessmah Посмотреть сообщение
А если объект содержит указатели на свои собственные члены?
Смотря на какие. С указателями на методы при этом ничего не случится.
А если с указателями на члены данных или на самого себя в подобъектах...
То в подавляющем большинстве случаев это говорит о концептуальной кривокостыльности некоторых решений ошибочно считаемых синтаксическим сахаром (например не нативных свойств). Так же в прочем не менее кривая идея хранить подобные объекты в однотипном массиве не допускающем динамического полиморфизма а не хранить массив указателей на них. В любом случае копирование через конструкторы существенно снижает производительность соответственно стоило бы иметь как минимум два типа контейнеров на эту тему (либо средства управления политикой копирования), при этом при внесении в стандарт нативных свойств использование контейнеров с копированием через деструкторы/конструкторы было бы в районе 0% случаев.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 23:20
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
То в подавляющем большинстве случаев
Поэтому надо сделать вектор так, чтобы оно не работало?

Цитата Сообщение от MrGluck Посмотреть сообщение
то какая разница?
Цитата Сообщение от hoggy Посмотреть сообщение
шо за дисриминацио?
Об этом лучше спросить здесь: https://www.cyberforum.ru/abou... 40069.html
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
18.01.2017, 23:24
Цитата Сообщение от Croessmah Посмотреть сообщение
Поэтому надо сделать вектор так, чтобы оно не работало?
Та он и так пригоден только для хранения тривиальных типов. Потому что не имеет средств взаимодействия с хранимыми элементами.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 23:28
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Потому что не имеет средств взаимодействия с хранимыми элементами.
Потому что ему это не нужно.
Он не для этого предназначен.

P.S. И не надо сейчас писать про "умные" контейнеры в билдере.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
19.01.2017, 00:18
Цитата Сообщение от Croessmah Посмотреть сообщение
Потому что ему это не нужно. Он не для этого предназначен.
То бишь быть контейнером нетривиальных типов он не предназначен в принципе, так же как и массивом слабых указателей. При этом хранить объекты в однотипном массиве а не массив указателей на них имеет хоть какой то смысл (обеспечение локальности данных) только пока размер объекта меньше 32 байт. Ну а что касается указателей на члены данных или самого себя - то реальную необходимость в подобных фортелях видел разве что в костыле под названием "не нативная реализации свойств". Т.е. получается в следствии редкости подобных фортелей стоило бы сделать политику реаллокации/подвижек управляемой так же как и политику ресайза.

Добавлено через 5 минут

Не по теме:

Цитата Сообщение от Croessmah Посмотреть сообщение
P.S. И не надо сейчас писать про "умные" контейнеры в билдере.
PS: Они там не "умные" а либо массивы слабых указателей либо слабо владеющие



Добавлено через 17 минут
Цитата Сообщение от Croessmah Посмотреть сообщение
Потому что ему это не нужно.
Ну да. Типа получается по тому же принципу что строка ноль как признак конца строки пользовать и явно хранить обязана но при записи ноля в нее длину подправлять не умеет, она типа для этого не предназначена, ей это типа не надо.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
19.01.2017, 00:20
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Та он и так пригоден только для хранения тривиальных типов. Потому что не имеет средств взаимодействия с хранимыми элементами.
Не имеют? Что за белиберда! Стандартные контейнеры имеют средства взаимодействия со своими элементами, и имеют именно и только те средства взаимодействия со своими элементами, который им нужны для хранения любых типов. Ни о каком "пригоден только для хранения тривиальных типов", разумеется, речи быть не может. Скорее было бы наоборот...

Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Ну а что касается указателей на члены данных или самого себя - то реальную необходимость в подобных фортелях видел разве что в костыле под названием "не нативная реализации свойств".
"Реальную необходимость видел разве..." - это лишь способ дань понять окружающим, что возразить нечего. Мало ли что там кто-то "видел" или "не видел"...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.01.2017, 00:20
Помогаю со студенческими работами здесь

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

Монета брошена 800 раз. Найти вероятность того, что «герб» выпадет на 20 раз больше, чем решка
Решите пожалуйста)

Используя статическую компоненту класса подсчитать количество созданных в программе объектов
Задание: Используя статическую компоненту класса подсчитать количество созданных в программе объектов. Статическую компоненту класса я...

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

Почему таймер срабатывает несколько раз?
Доброго времени суток, друзья. Нужен таймер, по прошествии которого выполняется программа. Создаю таймер: Timer time = new Timer(); ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru