LINUX.ORG.RU

С++ удаляет локальные переменные

 


0

1

Узнал ужасную вещь. С++ удаляет локальные переменные.
Допустим создал я объект

Myclass xxx;
xxx.onready = func
xxx.start();

Создался объект, запустил start... Иии... Умер. Потом с++ запускает деструктор объекта. А мой колбек onready не дождется своего выхода.
Это нормально? Я же сам не удалял объект через delete. То есть получается компилятор сам за меня решает?

★★★★

Последнее исправление: cetjs2 (всего исправлений: 2)

Не компилятор, а стандарт языка.

Когда переменная на стеке выходит из области видимости, то вызывается деструктор. Всё верно.

Компилятор тоже может удалить, если докажет, что поведение программы не изменится.

Вот например: https://gcc.godbolt.org/z/exaYPq

Нет new/delete. Компилятор это убрал…

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 2)
Ответ на: комментарий от fsb4000

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

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

по-разному. Нужно разобраться с временем жизни объекта. Кто отвечает за то когда объект умрёт? Если это в методе какого-то класса ты создаёшь объект, то может это не локальная переменная, а член класса?

можно std::unique_ptr хранить, или просто указатель, или std::optional

fsb4000 ★★★★★
()
Ответ на: комментарий от gobot

да. это либо делают в main, тогда в start бесконечный цикл, и она просто не завершится, пока будет нужна (ну там условие выхода из цикла). либо нужно размещать в куче (ну или еще где-то). make_shared например.

zerhud
()
Ответ на: комментарий от Harald

Не правильно все это. Я не давал команды удалять объект. Он должен жить, а в колбеке он уничтожится по моей команде

gobot ★★★★
() автор топика
Ответ на: комментарий от fsb4000

Кто отвечает за то когда объект умрёт?

Функция колбек

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

если старт() не блокирующий, то да на указателях, да и это же вопрос знания языка - время жизни объектов созданных на стеке приходится на блок в котором те объявлены и деструктор будет вызван по выходу из блока, время жизни указателя между вызовами new и delete соответственно.

AKonia ★★★
()
Последнее исправление: AKonia (всего исправлений: 2)
Ответ на: комментарий от gobot

нет, это время жизни объекта. это так называемая автоматическая память. объект создается на стеке и уничтожается после выхода за scope (независимо от того, есть на него ссылки или нет). если такое поведение не устраивает, нужно использовать тормазнутое выделение на куче.

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

zerhud
()
Последнее исправление: zerhud (всего исправлений: 1)
Ответ на: комментарий от gobot

«Правильно» или «неправильно» - это решает стандарт языка. Не нравится - используй другой язык (или пиши свой, как многие лор-овцы практикуют). Обычно, это всё выглядит так:

int main() {
  MyClass driver;
  driver.RegisterCallback(...);
  return driver.Wait(); // Wait for notification(s)
}

// or

int main() {
  MyClass driver;
  driver.RegisterCallback(...);
  return driver.BusyLoop(); // Execute tasks in the queue
}

Опционально, можно (но не всегда нужно) ждать в деструктoре.

anonymous
()
Ответ на: комментарий от gobot

Пойду наложу кучу…

Ты же тут хвастался недавно, что выучил C++, я думал тебя на работу позвать, а то у меня ни один плюсовик (включая меня) не знает C++

BackDoorLover
()
Ответ на: комментарий от gobot

ну, в кратце..

память приложеиня делаится на несколько сегментов. мы возьмем два - стек и куча. стек это очень быстрая автоматическая память. туда помещаются все объекты, которые создаются непосредственно в коде. например если просто написать int a; то этот а будет создан на стеке. это операция практически ничего не стоит. переменная будет удалена после того, как управление выйдет из области, где она определена.

вот пример

int bar(){
   int a=0;
   foo();
   return 0;
}
переменная a создана на стеке. когда она удалится? если все пойдет хорошо, то поесле интсрукции return;. а если функция foo(); выбросит исключение, то удалится на этом исключении.

куча - это память, котарая управляется программистом. она более медленная, так как каждый раз (ну есть некие оптимизации, но об этом лучше не думать), эта память запрашивается из системы. то есть ее получение - довольная медленная штука. поскольку она управляется программистом, то ее получение инициируется специальной командой и удаление тоже специальной командой. само по себе ничего не проиходит. тут есть подводные камни. вот тот же пример, но с кучей.

int* bar(){
    int* a=new int();
    foo();
    return a;
}
тут переменная а была создана на куче, с помощью оператора new. когда она будет удалена? в этом коде нет такой инструкции, так что коду, который вызвал bar нужно удалять ее самому (сказать int* delme=bar(); delete delme;). но, возможно, что foo выбросит исключение, тогда эта переменная не будет удалена никогда. это печаль, потому что однажды у системы не останется оперативной памяти для новой переменной.

есть еще умные указатели. они урпощаются жизнь с кучей, правда добавляют некоторых новых проблем (типа циклических ссылок...).

zerhud
()

К всевидящему All.

Тут недавно до усрачки некоторые в одной теме спорили, мол «плюсы» надо с STL учить, да и вообще, её и концепции ООП хватит всем. Ну да, ну да :D

Stack77
()
Ответ на: комментарий от BackDoorLover

как просто )) // смотри, чтобы коллеги не начали читать доки

anonymous
()
Ответ на: комментарий от gobot

Я не давал команды удалять объект.

Вообще-то, давал. Ты сказал: «создать объект на стеке здесь и удалить его при выходе из области видимости».

Он должен жить

Есть разница между тем, что ты хочешь сказать, и тем, что ты говоришь. Ты сказал уничтожить при выходе из области видимости, компилятор и вставил вызов деструктора в момент выхода из области видимости. Так что всё правильно.

i-rinat ★★★★★
()

Я же сам не удалял объект через delete

Локальные переменные называются иногда по другому - автоматические.

cloun1901
()
Ответ на: комментарий от gobot

Не правильно все это. Я не давал команды удалять объект. Он должен жить, а в колбеке он уничтожится по моей команде

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

используй динамическую память и тогда сам создавай где хочешь и удаляй когда хочешь... хотя судя по твоим познаниям есть вероятность наткнуться на out of range и прочие UB

jo_b1ack ★★★★★
()
Ответ на: комментарий от gobot

Блин, ну что значит неправильно. Такой язык.

rumgot ★★★★★
()
Ответ на: комментарий от gobot

Ты и команды создавать не давал. Че ты ждешь, что за тебя угадывать будут? Может еще кашу за тебя доесть или мануал прочитать? Совсем обалдели молокососы.

anonymous
()
Ответ на: комментарий от cloun1901

Автоматическими называются объекты.

А локальная переменная может быть и статической. (Быть объявлена с модификатором static).

anonymous
()
Ответ на: комментарий от anonymous

Ты и команды создавать не давал.

[intro.object]/1: «An object is created by a definition…». Myclass xxx; здесь это definition.

anonymous
()
Ответ на: комментарий от anonymous

Автоматическими называются объекты.

Хоть тот к данному товарищу не испытываю особой любви, он прав. Автоматическими называются переменные, которые определены внутри блока, такого как тело функции или блок внутри него. Разумеется, переменных, которые объявлены с ключевым словом static - это не относится.

rumgot ★★★★★
()

Узнал ужасную вещь.

Добро пожаловать в реальный мир.

Хочешь, чтобы объект жил после выхода из создавшей его функции — создавай его на куче через new. Но в этом случае надо озаботиться, кто его будет потом удалять, т.е. куда-то надо вернуть указатель на созданный объект.

Если твоя функция — метод другого класса, время жизни которого превышает время создаваемого, можно этот указатель сделать полем класса и удалять объект в деструкторе объемлющего класса. Во многих случаях такая схема оптимальна (но надо смотреть, как у тебя в программе объекты построены).

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

через new

Не учи человека плохому.

anonymous
()
Ответ на: комментарий от anonymous

Единственный правильный совет в топике. У ТС типичная XY проблема – он не понимает, как работают области видимости, и он борется с ними. Аллоцирует он память, дальше что? Это никак не поможет в решении проблемы, но добавит проблемы с динамическим выделением памяти. std::unique_ptr, кстати, если его никуда не передать, тоже освободит память при выходе из скоупа.

Нужно разбираться в том, какие переменные сколько должны жить, и что вообще нужно сделать. Из того, что я знаю, скорее всего нужно подождать, пока ffmpeg пережует входной файл. Это делается не так. Если ffmpeg запускается в отдельном процессе, нужно не делать спинлок на коленке, а использовать аналог waitpid в WinAPI. Это устранит проблему в корне.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 2)

У вас объект - часть стекового фрейма и он удаляется вместе с удалением стекового фрейма при окончании функции (на самом деле ещё есть вложенные области видимости но не будем усложнять). Тоже самое будет с полем класса при удалении класса, у поля вызовется деструктор. Если нужно чтобы деструктор не вызывался, нужно использовать указатель и Myclass *xxx = new Myclass(). В таком случае удалить объект и вызвать деструктор можно будет в любом указанном месте.

Даже если вы сделаете чтобы деструктор не вызывался (например с помощью placement new) стековая память всё равно будет удалена по окончанию функции и будет перезаписана при вызове другой функции, так что пользоваться переменной на стеке после окончания функции нельзя.

Я же сам не удалял объект через delete.

delete применим только для объектов на куче (то, что создано с помощью new), а не для переменных на стековом фрейме или полей класса. Вы видимо путаете со скриптовыми языками вроде JavaScript или Python где всё является указателями и часто новые объекты создаются на куче без явного new, например a = {};.

★★★★

Неожиданный вопрос для четырёх звёзд.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от gobot

Интуитивно понимаю, что это глобальная область?

Глобальная в рамках процесса. У каждого процесса своя куча.

X512 ★★★★★
()

Ну ты про деструкторы бы почитал. Это даже в шарагах рассказывают. Примерно тогда я понял что хочу иметь как можно меньше дел с C++

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

так ведь это не c++-специфичная проблема, а всех языков без сборки мусора. Например, в расте он бы задолбался отлаживать ошибку «что-то там doesn’t live long enough» при попытке передать коллбек в этот объект)

Lrrr ★★★★★
()
Ответ на: комментарий от peregrine

А финализаторы в C#/Java это принципиально другое, ага.

Siborgium ★★★★★
()
Ответ на: комментарий от Lrrr

Проблема c++ в том, что у него слишком много проблем и нюансов.

peregrine ★★★★★
()
Ответ на: комментарий от gobot

Первый комментатор всё правильно написал. Даже такому чайнику как я понятно, что описанной проблемы не было бы, если бы вы осилили хотя бы одну книжку про плюсам. Потому что в любой книге рассказывают про время жизни объектов. В данном случае можно создать объект не на стеке, а с помощью оператора new.

andalevor ★★★
()
Хоп, топ, Linux-у кирдык.
С C++ по дорожке - милый стриж!
Нубы не спешат,
Только знай себе твердят:
"Топ, топ, очень нелегки
В UB первые шаги.
А C++ дорожка так длинна -
Прямо к небу тянется она".
anonymous
()

@gobot не слушай ни кого, они тебе завидуют

anonymous
()
Ответ на: комментарий от anonymous

Автоматическими называются объекты.

А локальная переменная может быть и статической.

Ты всё перепутал. Но давай я тебе помогу - рассматривай ответы в этом топике в контексте поставленной в ОП проблемы, а не в контексте своих фантазий.

cloun1901
()
Ответ на: комментарий от gobot

Неправильно, конечно. Память нынче дешевая, объекты можно вообще не удалять, чтобы не фрустрировать макак.

anonymous
()
Ответ на: комментарий от gobot

Неправильно то, что ты не пишешь по стандартам, а воюешь с компилятором. А он все правильно делает

Aswed ★★★★★
()

А мой колбек onready не дождется своего выхода.

Твой коллбек вообще ничего не знает ни о Myclass, ни о xxx.

seiken ★★★★★
()

Хозяйке на заметку - низкоуровневое проектирование любых программ на языках без сборщика мусора, стоит начинать с политики владения объектов друг другом и их времён жизни.

pon4ik ★★★★★
()
Ответ на: комментарий от gobot

Колбек, это же просто адрес, число.

Myclass xxx;
xxx.some_number = 8;
xxx.start();

Не будешь удивляться, если эта переменная удалится? Число же стоит, где же моя восьмерка подевалась, беда.

vlad9486
()
Ответ на: комментарий от vlad9486

Вот как в языке без сборки мусора сопроводительное приходится: указатель это просто число, ничего более.

anonymous
()
Ответ на: комментарий от anonymous

сопроводительное *Страдать

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.