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

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

18.01.2017, 16:35. Показов 10334. Ответов 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip . . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru