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

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

18.01.2017, 16:35. Показов 10201. Ответов 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
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
19.01.2017, 00:46
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
это лишь способ дань понять окружающим, что возразить нечего
Это лишь реальная причина не пользовать ни vector ни прочую муть из набора STL которая имеет все что не нужно вместо того что реально необходимо контейнерам и указателям при правильном проектировании иерархии

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Который им нужны для хранения любых типов
При этом начнем с того что принципы хранения объектов (а особенно указателей на них) и тривиальных типов кардинально противоположны. Хотя бы исходя из того что тривиальный тип штука пассивная, а вот объект штука не просто активная а автономная, способная сама принимать решения в каком/каких контейнерах ему когда находится и когда удалится. При этом в большинстве случаев контейнер или использующий его код полнотой информации необходимой для принятия решения по конкретному объекту не владеет (ей владеет только сам объект), в отличии от элементов тривиальных типов.

Добавлено через 9 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Стандартные контейнеры имеют средства взаимодействия со своими элементами
Ни каких средств взаимодействия они не имеют. Потому что хранимый элемент даже не подозревает что он хранится в контейнере а соответственно и взаимодействовать с контейнером не может. Опять же само понятие "взаимодействие с контейнером" доступно только для объектов но не для тривиальных типов которые являются пассивными данными и кода который способен взаимодействовать с чем либо не имеют.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 11:50
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
либо средства управления политикой копирования
Они есть, называются std::is_trivially_copyable. Пингуй себе тривиальность копирования, да переключайся с копирования через memcpy на копирование циклом. Другой вопрос - пользуется ли этим ваша реализация STL.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.01.2017, 16:29  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Разрешается как замещать глобальный ::operator delete(void *), так и перегружать статическую функцию operator delete(void *) в конкретных классах.
Как заместить глобальный ::operator delete(void *) не нашел. Можете показать пример? Так же интересно зачем это может понадобится. Наверное для выделения памяти со специфичным выравниванием?

При замещении судя по всему прежний ::operator delete(void *) уже потеряется?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
19.01.2017, 16:42
Цитата Сообщение от sys_beginner Посмотреть сообщение
Наверное для выделения памяти со специфичным выравниванием?
Подробности есть у Майерса.
Мы может специализировать операторы работы с дин. памятью когда хотим оптимизировать работу с памятью. Дело в том, что new (new[]) старается быть максимально универсальным, само собой чем-то приходится жертвовать.
1
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 16:43
Цитата Сообщение от sys_beginner Посмотреть сообщение
Так же интересно зачем это может понадобится.
Как зачем? В своей программе на десять строчек вы вызываете стандартный глобальный operator new и получаете компактный exe-файл всего на сто (триста, 100500) килобайт. Потому что вместе с одной функцией operator new, вам прилинковали всю стандартную библиотеку. А возможности потребности линковать код одной функции у вас нет, потому что авторам компилятора в лом мужик, ну ты же не по диалапу программу распространять будешь? Ну вот и не занимайся крохоборством.

После этого вы матюкаетесь и пишете свой operator new, который делает ровно тоже что и стандартный, только мегабайты мусора за собой не тащит. Впрочем, для таких страдальцев где-то были и готовые решения аля "урезанный STL".
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.01.2017, 16:46  [ТС]
MrGluck,
Я чушь написал)) Думал об operator new а писал про delete)) Он ж ничего не выравнивает

Цитата Сообщение от MrGluck Посмотреть сообщение
Дело в том, что new (new[]) старается быть максимально универсальным, само собой чем-то приходится жертвовать.
А в чем универсальность?

Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
В своей программе на десять строчек вы вызываете стандартный глобальный operator new
Не понял как operator new связан с экзешником?

Добавлено через 32 секунды
Цитата Сообщение от Renji Посмотреть сообщение
В своей программе на десять строчек вы вызываете стандартный глобальный operator new
Не понял как operator new связан с экзешником?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 16:54
Цитата Сообщение от sys_beginner Посмотреть сообщение
Не понял как operator new связан с экзешником?
Исполняемый файл вызывает operator new -> компилятор добавляет в исполняемый файл код реализующий operator new->exe-файл становится тяжелее. Очень сильно тяжелее, так как добавлять только код используемой функции не в моде. Когда-то это было оправдано экономией времени компиляции (компилировать стандартную библиотеку долго, лучше готовый шмат кода возьмем), сейчас геморрой один.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.01.2017, 16:59  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Очень сильно тяжелее, так как добавлять только код используемой функции не в моде.
не допёр а что ещё нужно добавлять кроме кода используемой функции, в данном случае operator new?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
19.01.2017, 17:11
Цитата Сообщение от sys_beginner Посмотреть сообщение
А в чем универсальность?
Данные сразу затираются. Выделение идёт под каждый объект отдельно. Никаких доп. действий.
При перегрузке оператора new:
Можно вместо освобождения памяти, закешировать указатель на участок и потом записывать туда новый объект.
Можно выделять память сразу под несколько объектов.
Можно логировать выделение/освобождение, накладывать дополнительные проверки.
Кроме того, стандартный new может выделять под объекты чуть больше памяти, чем требуется. Иногда это не подходит для ряда задач.
1
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 17:16
Цитата Сообщение от sys_beginner Посмотреть сообщение
не допёр а что ещё нужно добавлять кроме кода используемой функции, в данном случае operator new?
Добавить надо только понятный процессору машинный код operator new. Но этого кода у компилятора нет. Есть только заранее запасенный монолитный шмат машинных кодов, где-то внутри которого затерялся operator new. Отделить от этого шмата код одной функции компилятор не может (из-за потенциальных зависимостей от шмата), а потому весь шмат и цепляет.

Вместо этого компилятор мог бы взять исходный код operator new и сгенерировать нужный машинный код налету. Но когда таких operator new набирается много, это уже требует значительных системных ресурсов. Так что авторы компиляторов на такой ход традиционно забивают. Ну, в крайнем случае пилят заранее заготовленный шмат кода на шматики помельче (но все равно избыточные).
2
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.01.2017, 17:23  [ТС]
Цитата Сообщение от MrGluck Посмотреть сообщение
Можно вместо освобождения памяти, закешировать указатель на участок и потом записывать туда новый объект.
Так собственные аллокаторы никто не отменял Можно же ими обойтись
Цитата Сообщение от MrGluck Посмотреть сообщение
Можно выделять память сразу под несколько объектов.
Тоже можно собственным аллокатором
Цитата Сообщение от MrGluck Посмотреть сообщение
Можно логировать выделение/освобождение, накладывать дополнительные проверки.
Тоже можно собственным аллокатором

Т.е не перегружать new а создать просто отдельную сущность - аллокатор
Цитата Сообщение от MrGluck Посмотреть сообщение
Кроме того, стандартный new может выделять под объекты чуть больше памяти, чем требуется. Иногда это не подходит для ряда задач.
Можно пожалуйста подробнее?
Зачем ему выделять больше памяти?
Где это может не подойти за исключением того то памяти жалко

Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
Добавить надо только понятный процессору машинный код operator new. Но этого кода у компилятора нет. Есть только заранее запасенный монолитный шмат машинных кодов, где-то внутри которого затерялся operator new. Отделить от этого шмата код одной функции компилятор не может (из-за потенциальных зависимостей от шмата), а потому весь шмат и цепляет.
Вместо этого компилятор мог бы взять исходный код operator new и сгенерировать нужный машинный код налету. Но когда таких operator new набирается много, это уже требует значительных системных ресурсов. Так что авторы компиляторов на такой ход традиционно забивают. Ну, в крайнем случае пилят заранее заготовленный шмат кода на шматики помельче (но все равно избыточные).
Спасибо! Я правильно понимаю, это делает программу медленнее?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 17:29
Цитата Сообщение от sys_beginner Посмотреть сообщение
Спасибо! Я правильно понимаю, это делает программу медленнее?
Нет, только жирнее из-за обилия недостижимого кода. А так, этот код, при современных механизмах отображения файлов в память, даже оперативной памяти занимать не должен (нет обращений->не подгружается с диска). Но все равно не особо приятно когда такой мусор фактически занимает этак половину небольшого exe-шника.
1
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
19.01.2017, 17:30
Цитата Сообщение от sys_beginner Посмотреть сообщение
Можно пожалуйста подробнее?
Я уже в третий раз пишу - подробнее рассмотрено в книге у Майерса.
Цитата Сообщение от sys_beginner Посмотреть сообщение
можно собственным аллокатором
Аллокатор пишется для контейнеров. Мы же перегружаем new для классов, таким образом, контролируем выделение памяти для объектов класса, неважно в чём они лежат.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Зачем ему выделять больше памяти?
Например потому, что удобнее выделять память блоками определённых размеров. И никто не запрещает ему выделить больше памяти.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Где это может не подойти за исключением того то памяти жалко
Там, где мы последовательно перебираем блоки определённых размеров в памяти.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.01.2017, 17:39  [ТС]
Цитата Сообщение от MrGluck Посмотреть сообщение
Аллокатор пишется для контейнеров.
В смысле для контейнеров? Имеется ввиду STL?
Аллокатор вроде бы должен просто предоставлять доступ к памяти по определенной стратегии думаю не важно контейнеры используют эту память или кто то другой

Цитата Сообщение от MrGluck Посмотреть сообщение
Там, где мы последовательно перебираем блоки определённых размеров в памяти.
Ну не знаю. Обычно это массивы и их реализация гарантирует правильную последовательность элементов в памяти
но не исключаю что может бы специфичная задача
возьму на заметку, спасибо

Добавлено через 2 минуты
Renji,
В целом понял, спасибо
Только не очень понял зачем все таки компиляторам требуется этот дополнительный код (с точки зрения реализации)
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
19.01.2017, 17:50
Цитата Сообщение от sys_beginner Посмотреть сообщение
Зачем ему выделять больше памяти?
Под свои данные? Например, для так называемого некоторыми незнающими людьми "динамического массива" в с++ может выделяться кусок памяти, который будет содержать размер этого массива и указатель на начало.
Но это не точно! Может сейчас это строго регулируется стандартом, не проверял.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.01.2017, 17:56
Цитата Сообщение от sys_beginner Посмотреть сообщение
Зачем ему выделять больше памяти?
Например, для buddy memory allocation. Очень шустро, но весьма значительная часть доступной памяти вылетает в трубу.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Только не очень понял зачем все таки компиляторам требуется этот дополнительный код (с точки зрения реализации)
С точки зрения реализации, компилятор обрабатывает каждый cpp независимо и получает из него отдельный шмат кода. А линкер потом просто склеивает эти шматы вместе. При этом компилятор понятия не имеет используется ли этот шмат в принципе (он же в соседние cpp не смотрит), а линкер понятия не имеет как отделить нужное от ненужного.
Теперь компилятор и линкер вроде как стали умнее, но схема "зачем голову забивать? Прилепим готовый шмат и дело с концом" продолжает жить.
1
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
19.01.2017, 17:58
Цитата Сообщение от GbaLog- Посмотреть сообщение
для так называемого некоторыми незнающими людьми "динамического массива" в с++ может выделяться кусок памяти, который будет содержать размер этого массива и указатель на начало.
Стандартом это не определяется, но обычно размер хранится до первого элемента массива. Это платформозависимая вещь.
Указатель на начало массива совпадает с указателем на первый элемент массива. Это не нужно нигде хранить.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
19.01.2017, 17:59
Цитата Сообщение от sys_beginner Посмотреть сообщение
Как заместить глобальный ::operator delete(void *) не нашел. Можете показать пример? Так же интересно зачем это может понадобится. Наверное для выделения памяти со специфичным выравниванием?
При замещении судя по всему прежний ::operator delete(void *) уже потеряется?
Глобальный никак. Толь для каждого отдельно взятого типа.
Из C++ Language Reference
The global operators, ::operator delete(), and ::operator delete[]() cannot be overloaded. However, you can override the default version of each of these operators with your own implementation. Only one instance of each global delete function can exist in the program.
1
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
19.01.2017, 18:04
Цитата Сообщение от MrGluck Посмотреть сообщение
Это не нужно нигде хранить.
Ну это да, ошибочка. Но зато может понадобиться хранить размер и, к примеру, указатель на следующий и предыдущий блок. Тогда удаление за константу получаем, но оверхед по памяти. Тут реализаций много и, скорее всего, зависит от платформы, как вы и сказали.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
19.01.2017, 18:22
Цитата Сообщение от GbaLog- Посмотреть сообщение
Например, для так называемого некоторыми незнающими людьми "динамического массива" в с++ может выделяться кусок памяти, который будет содержать размер этого массива и указатель на начало.
Но это не точно!
Это точно. Поскольку operator delete[] каким то магическим образом определяет размер блока который нужно освободить. А поскольку мы люди науки в суеверия не верим то точно знаем что всяка подобна магия и прочие мракобесия находится под капотом у менеджера кучи. А вот где и каким способом он этот размер хранит уже зависит от реализации оного менеджера.

Добавлено через 12 минут
Цитата Сообщение от sys_beginner Посмотреть сообщение
чушь написал)) Думал об operator new а писал про delete)) Он ж ничего не выравнивает
Обычно их нужно создавать парой. Причем применение может быть разным. Например реализация пула объектов. Или выделение памяти не в системном озу а к примеру аки буфера DirectX живущего в видеокарте. В общем своя реализация менеджера кучи реализующего альтернативную модель распределения памяти для того или иного типа данных. Опять же в зависимости от размера распределяемой области оптимальны различные модели организации пометок занято/свободно под капотом менеджера кучи.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.01.2017, 18:22
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
80
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
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 была полностью переписана на Си, в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru