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

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

18.01.2017, 16:35. Показов 10233. Ответов 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
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
20.01.2017, 09:56  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от GbaLog- Посмотреть сообщение
Например, для так называемого некоторыми незнающими людьми "динамического массива" в с++ может выделяться кусок памяти, который будет содержать размер этого массива и указатель на начало.
Это понятно, потому что конкретная реализация делает это явно(та же реализация так называемого динамического массива).
Но там была именно речь о том что Type *t = new Type; может выделить памяти больше чем sizeof(Type)
Цитата Сообщение от MrGluck Посмотреть сообщение
Кроме того, стандартный new может выделять под объекты чуть больше памяти, чем требуется.
Вот...
И мне все таки не понятно зачем и в каких случаях такое может происходить. Максимальный оверхед который встречал от new это было в связано выравниванием а это по сути копейки и только на пользу. Иногда это вредно если например структуру хочется передать по сети, то тут уже sizeof не подходит и можно воспользоваться прагмой или вручную суммировать sizeof каждого элемента структуры. Хорошо было бы если MrGluck уточнил что он имеет ввиду
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
20.01.2017, 10:27
Цитата Сообщение от sys_beginner Посмотреть сообщение
И мне все таки не понятно зачем и в каких случаях такое может происходить.
Например, delete[] же должен знать сколько ему вызывать деструкторов.
А для этого ему нужно знать количество элементов, а значит их нужно где-то хранить,
например, выделить памяти чуть больше и поместить размер в самое начало.
Можно ли обойти динамический массив не зная его размер?
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
20.01.2017, 10:34  [ТС]
Croessmah,
Спасибо. Но там была оговорка что это не всегда может быть нужно
Кроме того, стандартный new может выделять под объекты чуть больше памяти, чем требуется. Иногда это не подходит для ряда задач.
В случае с delete[] это оправдано иначе UB. Больше интересует то где такое происходит и почему это может не подходить для этой задачи.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
20.01.2017, 10:45
Цитата Сообщение от sys_beginner Посмотреть сообщение
почему это может не подходить для этой задачи.
Если объект всего один (new),
то нет смысла пихать размер впереди.
По той же ссылке чуть ниже есть рисунок,
так же есть примерчики изменения этого хвоста.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
20.01.2017, 10:48  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Если объект всего один (new),
Честно говоря подумал об этом, но это показалось мне настолько незначительным что об этом даже не написал

Добавлено через 28 секунд
А примерчики посмотрю, спасибо )
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
20.01.2017, 11:29
sys_beginner, еще вариант - память выделялась,
например, под тип POD, или вообще под примитивы,
то есть ни о каких деструкторах речи не идет.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
20.01.2017, 11:32  [ТС]
Croessmah,
Ну если в таком случае хвост создается то это уже скорее проблема кривого компилятора Разве нет?
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
20.01.2017, 11:36
sys_beginner, не факт.
Всё же зависит от целей всего этого
и от мыслей разработчиков.
Что там в этом хвосте и есть ли он вообще -
определяется конкретной реализацией.
1
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
20.01.2017, 19:28
Цитата Сообщение от sys_beginner Посмотреть сообщение
Ну если в таком случае хвост создается то это уже скорее проблема кривого компилятора Разве нет?
Это вопросы менеджера кучи, и решает он их наиболее удобным путем на взгляд разработчика оного менеджера. К примеру большие блоки памяти удобно помечать свободно/занято расставляя в их начале указатель на следующий блок. и высвобождение константное по времени и оверхед по памяти не значительный, и размер блока всегда известен и сшить вместе свободные блоки тоже константная по времени тривиальная задача, и распределение по принципу "сначала дыры" тоже довольно шустрое, и количество удаляемых элементов в delete[] можно не указывать как это было в его золотом детстве, и в принципе промахи указателя указанного в delete на начало блока тоже выправлять можно но естественнно за счет оверхеда.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
21.01.2017, 20:42  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Например, если в коде выше убрать noexcept
у перемещающего конструктора,
то вектор будет использовать копирующий
конструктор, а не перемещающий.
Кажется я нашел ответ на этот вопрос. Не уверен что он точный, но в принципе логичный.

Для операций вставки у вектора, дека и контейнеров, которые основаны на std::array не предусмотрено "бросание исключений".
Если например операция вставки в вектор оказалось не удачной, то гарантируется что никаких последствий не будет в т.ч и исключений.
То есть либо получится вставить новый элемент, либо нет и ничего плохого не произойдет.

При вставке в вектор если есть возможность, используется конструктор перемещения для вставляемого элемента, иначе конструктор копирования
Ввиду того, что исключений для операций вставки в вектор не предусмотрено, для обеспечения поведения "либо получится вставить новый элемент, либо нет и ничего плохого не произойдет",
конструктор перемещения должен гарантировать что он не собирается бросать исключение, это обеспечивается ключевым словом noexcept.

В этом случае вектор имеет право использовать конструктор перемещения потому что для вставки нового элемента в вектор соблюдается принцип "не бросать исключение".
Если же перемещающий конструктор не соблюдает этот принцип, то при вставке нового элемента вектор не может полагаться на конструктор перемещения и использует конструктор копирования.

Добавлено через 46 минут
Если это описание к данному вопросу правильное, то почему если убрать noexcept у конструктора копирования добавление все равно происходит успешно http://rextester.com/CKBJU14850

Так же интересно почему копирование и перемещение в этом примере срабатывает успешно? Там же переопределены эти конструкторы а их тело пусто. Соответственно логика копирования и перемещения не реализована но тем не менее все работает. Как это понимать?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
21.01.2017, 21:16
Цитата Сообщение от sys_beginner Посмотреть сообщение
Ну если в таком случае хвост создается то это уже скорее проблема кривого компилятора Разве нет?
Вы же сами некоторое время назад поднимали тему, в которой в том числе обсуждалось и то, почему могут возникать разнообразные "хвосты"

Выравнивание адреса памяти
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
21.01.2017, 21:26  [ТС]
TheCalligrapher,
Все еще продолжаю изучение, и потому что постоянно что-то читаю по С++ некоторая информация полученная ранее частенько вылетает из головы...
Видимо HD в голове не большой ))
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
21.01.2017, 22:31
Цитата Сообщение от sys_beginner Посмотреть сообщение
Если например операция вставки в вектор оказалось не удачной, то гарантируется что никаких последствий не будет в т.ч и исключений.
Гарантируется что контейнер останется в неизменном состоянии, если элементы можно перемещать без исключений или хотя-бы копировать с исключениями. Сами исключения никто не запрещал.
А вот под какими надо было быть веществами чтобы трактовать noexcept не как No-throw guarantee с UB в случае броска исключения, а как catch(...){std::abort();} это, действительно, загадка. Зашибись логика - пишешь компилятору "да нету у меня здесь исключений, нету! No-throw guarantee здесь!", а он кивает головой "ну раз нету, я тут код для обработки не существующих исключений добавлю, ладно?".
2
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
22.01.2017, 00:11  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Гарантируется что контейнер останется в неизменном состоянии, если элементы можно перемещать без исключений или хотя-бы копировать с исключениями.
Понятно, спасибо! Насколько я понял если элементы вектора соответствуют гарантиям, в данном случае гарантиям по части конструктора перемещения, то будет использован конструктор перемещения. Но это немного странно, чем объясняется такая избирательность? Копированию можно бросать исключение, а перемещению - нет. Кстати, можете пожалуйста процитировать стандарт где об этом написано?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.01.2017, 03:21
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но это немного странно, чем объясняется такая избирательность?
Тем что перемещающий конструктор имеет право изменять источник перемещаемых данных. И будет очень весело, если сбойнет он как раз в процессе этого изменения. Копирующий же конструктор имеет доступ к копируемым данным только по константе.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Кстати, можете пожалуйста процитировать стандарт где об этом написано?
Я брал информацию с www.cplusplus.com . Ну и чуток попутал - гарантия неизменности дается только для вставки элемента в конец вектора. В остальных случаях дается только гарантия корректного состояния.

If the operation inserts a single element at the end, and no reallocations happen, there are no changes in the container in case of exception (strong guarantee). In case of reallocations, the strong guarantee is also given in this case if the type of the elements is either copyable or no-throw moveable.
Otherwise, the container is guaranteed to end in a valid state (basic guarantee).
1
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.01.2017, 17:35
Цитата Сообщение от Renji Посмотреть сообщение
А вот под какими надо было быть веществами чтобы трактовать noexcept не как No-throw guarantee с UB в случае броска исключения, а как catch(...){std::abort();} это, действительно, загадка. Зашибись логика - пишешь компилятору "да нету у меня здесь исключений, нету! No-throw guarantee здесь!", а он кивает головой "ну раз нету, я тут код для обработки не существующих исключений добавлю, ладно?".
Как раз все сделано грамотно, а предложение, что лучше UB - просто ужасно.
Оверхеда не дается никакого, зато в случае человеческой ошибки мы получаем быстрое падение и дамп, что много лучше странных и трудновоспроизводимых багов.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.01.2017, 17:43
Цитата Сообщение от ct0r Посмотреть сообщение
Как раз все сделано грамотно, а предложение, что лучше UB - просто ужасно.
Тогда почему return в [[noreturn]] функции это UB?
Цитата Сообщение от ct0r Посмотреть сообщение
Оверхеда не дается никакого, зато в случае человеческой ошибки мы получаем быстрое падение и дамп, что много лучше странных и трудновоспроизводимых багов.
Никакого дампа мы не получаем, так как вызываемый при броске исключения std::terminate этих самых дампов не генерирует. Зато получаем лишних сто кило мусора, прилинкованных к деструктору (noexcept автоматом) не использующему ничего кроме WinAPI (там очень часто генерируются исключения, ага).
0
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
22.01.2017, 19:50
Цитата Сообщение от Renji Посмотреть сообщение
Тем что перемещающий конструктор имеет право изменять источник перемещаемых данных. И будет очень весело, если сбойнет он как раз в процессе этого изменения. Копирующий же конструктор имеет доступ к копируемым данным только по константе.
Это что ж с ним делать то надо чтобы оно засбоило? На нул не проверять по каким адресам ходишь или сверху из вызывающей надпрограммы невалидный указатель втулить ненулевой, что с самой передаваемой ему ссылкой сделать проблемно, а вот в указателях которые по этой ссылке лежат такая подлянка чисто теоретически может оказаться (хотя такое должно на этапе отладки искореняться). А вот из копируещего конструктора который имеет обычай память распределять можно действительно от new экскепшн схлопотать сколько не отлаживай, и вышестоящих оповестить что все куча закончена другого способа кроме экскепшина тоже нет. При этом от того что доступ по константе был не холодно ни жарко так как сам факт что что то не скопировалось в принципе может трактоваться как отказ системы. Опять же сам вектор для того чтобы неизменность при копировании гарантировать должен иметь оповещения что какой то конструктор копирования не сработал и откатить реаллок. А для конструктора перемещения по всей видимости считается что перемещение неубиваемое если место куда перемещать распределено до вызова конструктора и у того кто писал сам конструктор и заполнял то что ему передается для перемещения руки хоть немного прямые.

Добавлено через 6 минут
А то что константные/не константные это как то к делу не относится по всей видимости. Хотя бы потому как на каждый const найдется свой mutable.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.01.2017, 20:09
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Это что ж с ним делать то надо чтобы оно засбоило?
Добавить в класс единственный std::string. У него конструктор по умолчанию стал noexcept только в C++17. А до этого теоретически мог плюнуть исключением. Хотя, я слабо себе представляю как и зачем.
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Опять же сам вектор для того чтобы неизменность при копировании гарантировать должен иметь оповещения что какой то конструктор копирования не сработал и откатить реаллок.
Ну так он их и имеет, "catch секция" называется.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.01.2017, 20:20
Цитата Сообщение от Renji Посмотреть сообщение
Тогда почему return в [[noreturn]] функции это UB?
По поводу noreturn было много споров в комитете, поэтому вопрос скользкий. По крайней мере ворнинги выдаются и поведение семантически эквивалентно соответствующим атрибутам самых распространенных компиляторов.

Цитата Сообщение от Renji Посмотреть сообщение
Никакого дампа мы не получаем, так как вызываемый при броске исключения std::terminate этих самых дампов не генерирует.
WAT? terminate вызывает abort, abort шлет SIGABRT, а что делается при принятии SIGABRT можно посмотреть в man 7 signal. (Подсказка: при выполнении программы появляется строка "Aborted (core dumped)".)

Цитата Сообщение от Renji Посмотреть сообщение
Зато получаем лишних сто кило мусора, прилинкованных к деструктору (noexcept автоматом) не использующему ничего кроме WinAPI (там очень часто генерируются исключения, ага).
Почему 100? Даже в случае вызова внутри только тех функций, которые noexcept?

Добавлено через 7 минут
И кстати раз уж что-то про винду, то https://msdn.microsoft.com/en-... eycx5.aspx - как можно оттюнить поведение.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.01.2017, 20:20
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
Новые блоги и статьи
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru