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

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

18.01.2017, 16:35. Показов 10181. Ответов 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
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 16:38
C++
1
2
    v.emplace(v.begin(), 1);//вставили в начало
    v.emplace(v.begin(), 2);//вставляем в начало, а контейнер не пуст. Значит нужно "сдвинуть" элементы
То бишь у Вас создается копия.
Добавьте свой копирующий конструктор.

А можете заменить
C++
1
2
    v.emplace(v.begin(), 1);
    v.emplace(v.end(), 2);
2
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.01.2017, 16:40
Цитата Сообщение от sys_beginner Посмотреть сообщение
Если описать деструктор, нужно ли описывать ещё и деструктор по умолчанию?
обязательно.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 16:41
Цитата Сообщение от hoggy Посмотреть сообщение
обязательно.
А копирующий деструктор?
4
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 16:44  [ТС]
Croessmah,
Да точно. Ступил. Насколько понял один объект перетирает другой и он вынужденно удаляется, из за этого вызывается деструктор.

Но что вы скажете на это? Порядок индексов вроде бы правильно соблюдается. Но конструктор вызывается 3 раза, а деструктор 5 раз.
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
#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()+1, 2);
    v.emplace(v.begin()+2, 3);
    std::cout << std::endl << v.capacity() << std::endl;
}
http://rextester.com/CNANS29975

Добавлено через 42 секунды
Цитата Сообщение от Croessmah Посмотреть сообщение
А копирующий деструктор?
Какой ещё копирующий деструктор?)))
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
18.01.2017, 16:44
Цитата Сообщение от sys_beginner Посмотреть сообщение
каким образом происходит освобождение памяти
В две стадии.
1. Тело деструктора.
2. operator delete.
Но это не точно!
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 16:47  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
обязательно
Понял. Так вроде нельзя ~Foo() = default; выдает ошибку
Насчет простых типов не нужно заморачиваться. Они будут созданы в стеке а когда встретится } память простых типов будет освобождена автоматически, верно?
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 16:50
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но что вы скажете на это?
Я уже сказал:
Цитата Сообщение от Croessmah Посмотреть сообщение
Добавьте свой копирующий конструктор.
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
38
39
40
41
#include <iostream>
#include <vector>
 
class Foo
{
    public:
    Foo(int n) noexcept
    {
        std::cout << "CONSTRUCT" << std::endl;
    }
    Foo(const Foo &) noexcept
    {
        std::cout << "COPY CONSTRUCT" << std::endl;
    }
    Foo(Foo &&) noexcept
    {
        std::cout << "MOVE CONSTRUCT" << std::endl;
    }
    Foo &operator=(const Foo &) noexcept
    {
        std::cout << "COPY ASSINGMENT" << std::endl;
    }
    Foo &operator=(Foo &&) noexcept
    {
        std::cout << "MOVE ASSINGMENT" << 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()+1, 2);
    v.emplace(v.begin()+2, 3);
    std::cout << std::endl << v.capacity() << std::endl;
}
http://rextester.com/RUJ68492
1
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
18.01.2017, 16:53
Цитата Сообщение от sys_beginner Посмотреть сообщение
Вопрос в заголовке темы. Почему? Создается всего 2 объекта, но деструктор вызывается трижды.
Потому что объекты должны располагаться в памяти строго друг за другом. Если сразу за объектами вектора место занято, то новые объекты пихать больше некуда. В этом случае вектор пытается скопировать свои данные в местечко попросторнее. А оригинал прибивает серией вызовов деструктора.
Ну а если автор вектора был ленив, то вектор вообще не будет проверять есть место под новый объект или нет, а сразу полезет искать местечко попросторнее.
1
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 16:54
Renji, в первом коде изначально резерв задан.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
18.01.2017, 16:56
Цитата Сообщение от Croessmah Посмотреть сообщение
Renji, в первом коде изначально резерв задан.
А, да, действительно, пропустил.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 17:00  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Добавьте свой копирующий конструктор.
Не понял а зачем свой копирующий конструктор если как оказалось остальные два раза вызвался конструктор перемещения? Это происходит из за реаллокации?

Цитата Сообщение от Renji Посмотреть сообщение
Потому что объекты должны располагаться в памяти строго друг за другом.
А у меня же плюсуются к begin индексы, это разве не приводит к тому что элементы в векторе начинают распологаться друг за другом?
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 17:05
Цитата Сообщение от sys_beginner Посмотреть сообщение
два раза вызвался конструктор перемещения?
уберите конструктор перемещения,
будет вызываться конструктор копирования.
Я добавил и то и другое, а еще operator=.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Это происходит из за реаллокации?
Да. Объекты же нужно в новую память скопировать.
Класс поддерживает move-семантику,
так что вполне можно объекты переместить,
а не скопировать, что, собственно и делается.

Добавлено через 55 секунд
Цитата Сообщение от sys_beginner Посмотреть сообщение
А у меня же плюсуются к begin индексы, это разве не приводит к тому что элементы в векторе начинают распологаться друг за другом?
Он о другом. Его ответ подходит под второй код,
т..к резерв задан на 2 элемента, а Вы пихаете три.
Соответственно, реаллокация происходит.
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.01.2017, 17:12
Цитата Сообщение от Croessmah Посмотреть сообщение
А копирующий деструктор?
а копирующий по желанию
я вот не пишу никогда, например...
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 17:13  [ТС]
Croessmah,

То есть когда происходит реаллокация, делается следующее:
1. Есть конструктор перемещения? Вызывается он потому что так оптимальнее
2. Если нету конструктора перемещения - вызывается конструктор копирования

Реаллокация насколько я понимаю требует очищения памяти всего вектора и создания нового массива под капотом самого вектора. То есть изначально для двух элементов было рарезервировано место. Потом добавился ещё 1 элемент и их стало 3. Первые два удалились из за реаллокации, были вызваны их деструкторы. Затем три объекта тоже удалились поэтому вызовов деструкторов было 5. Я прав?
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 17:25
Цитата Сообщение от hoggy Посмотреть сообщение
а копирующий по желанию
я вот не пишу никогда, например...
Я, в последнее время, тоже перестал.
Цитата Сообщение от sys_beginner Посмотреть сообщение
1. Есть конструктор перемещения? Вызывается он потому что так оптимальнее
Ну, как бэ да, но всё несколько сложнее.
Например, если в коде выше убрать noexcept
у перемещающего конструктора,
то вектор будет использовать копирующий
конструктор, а не перемещающий.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Первые два удалились из за реаллокации, были вызваны их деструкторы.
Концептуально сначала был выделен более здоровый кусок памяти,
куда уже может поместится
три наших элемента, затем
старые элементы нужно
скопировать или переместить
на новое место, затем удалить
старые элементы и освободить
старую память, т.к. более не нужна.
Соответственно, привести
инвариант вектора
в нормальное состояние.
Всё это делается "под капотом".
1
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
18.01.2017, 17:29
Цитата Сообщение от Croessmah Посмотреть сообщение
Я, в последнее время, тоже перестал.
А мне Вася сказал, что если не определить явно копирующий деструктор, то компилятор сгенерирует его по умолчанию.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
18.01.2017, 17:30
MrGluck, ну вот и я о том же.
Раньше я этого не знал.
Спасибо hoggy, научил.
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
18.01.2017, 17:32
А если серьёзно, то
12.4 Destructors
4. If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (8.4). An implicitly
declared destructor is an inline public member of its class.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
18.01.2017, 17:34  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Например, если в коде выше убрать noexcept
у перемещающего конструктора,
то вектор будет использовать копирующий
конструктор, а не перемещающий.
А как noexcept на это влияет? Он вроде просто говорит "умри" если будет исключение из метода, и даже если его поймают. Не понял почему оно влияет на ситуацию

Цитата Сообщение от Croessmah Посмотреть сообщение
Всё это делается "под капотом".
Ну я вроде такое и описал
Спасибо

Добавлено через 1 минуту
Цитата Сообщение от MrGluck Посмотреть сообщение
If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (8.4). An implicitly
declared destructor is an inline public member of its class.
А что он делает? Этот деструктор по умолчанию? Судя по всему - ничего. Потому что когда я определяю свой деструктор то только что бы освободить ресурсы вроде динамической памяти
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
18.01.2017, 17:34
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
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