скажем, у меня есть класс Foo, который я выделяю в куче с помощью ключевого слова ‘new’. Скажем, у Foo есть не указатель на элемент данных Bar. Bar, хотя и не является указателем, сам по себе находится в куче, поскольку он является частью Foo. Он будет должным образом освобожден, когда я удаляю свой объект Foo — даже если я объявляю свой собственный деструктор Foo, который не удаляет и не должен удалять Bar.
Есть ли какой-нибудь термин для элементов данных, таких как Bar, который, хотя и находится в куче, не создается с помощью ключевого слова «new»? Для объектов, не выделенных в стеке, но вызов деструктора обрабатывается автоматически.
Деструктор Foo по умолчанию все еще создается, хотя программист объявил и определил деструктор, который выполняется позже?
Если нет, то как называется деструктор Бара?
Учитывая стандартное правило, которое гласит: «Комитет не должен создавать никаких правил, которые мешают программистам C ++ стрелять себе в ногу», если я ХОЧУ создать утечку памяти на элементе данных без указателя, независимо от того, выделен ли стек или куча, как бы я Сделай так? (Примечание: я на самом деле не пытаюсь это сделать)
Во-первых, стандарт C ++ не имеет кучи. Имеется бесплатный магазин и автоматическое хранение.
Давайте посмотрим на конкретный пример, который соответствует вашему теоретическому:
struct Bar { int x[100]; }
struct Foo {
Bar bq;
int x;
~Foo() {};
};
Bar bq
является переменной-членом любого Foo
пример. Когда вы создаете Foo
в свободном магазине, его переменные-члены являются частью Foo
, Если Foo
стандартное расположение (как выше), вы в основном гарантированы, что его переменные-члены расположены в линейном буфере. Нестандартные объекты компоновки могут, в некоторых теоретических компиляторах, иметь экзотические макеты, но на практике они не имеют.
С выше Foo
Деструктор по умолчанию не создается. Тем не менее, для каждого деструктора Foo
предметы внутри Foo
уничтожены после тела Foo
Деструктор запущен. Обратите внимание, что уничтожение указателя ничего не делает — я имею в виду фактическую часть объектов Foo
,
Это не потому, что вызывается «автоматически созданный деструктор» — деструктор по умолчанию ~Foo() {}
так же, как то, что вы определили. Скорее, код автоматически запускается после завершения работы деструктора.
Единственный способ сделать Bar
не будет вызван деструктор, чтобы элемент данных не был Bar
, Есть несколько способов сделать это, включая создание Bar
размер и выравнивание буфера данных, затем размещение new
в Bar
,
Однако, пока деструктор не будет вызван, память, Bar
существует внутри будет переработан в бесплатном магазине, когда Foo
Bar
существует в переработано.
Если бы вы хотели Bar
утечка, вы заблокируете Foo
от возвращения в бесплатный магазин. Однако нет способа выделить Foo
из бесплатного магазина и возврата часть из Foo
в бесплатный магазин — вы можете вернуть только все это или ни одного. Вы можете создать свой собственный бесплатный магазин или свою собственную ручную кучу с этими свойствами, и ничто не остановит вас. Вы даже можете переопределить new
а также delete
так что ваша куча используется вместо бесплатного магазина, когда кто-то делает Foo* foo = new Foo()
и когда кто-то делает delete foo
,
Тем не менее, объем памяти, который Foo
занимает не находится под вашим контролем, ни относительное расположение каждой переменной-члена.
1) Это не волшебство, и нет никакого термина для этого. Когда вы выделяете место для Foo
, sizeof
Foo
включает размер всех его элементов данных, и эти элементы обычно выровнены по байту вдоль границ 4 байта. когда delete
называется, бухгалтерский заголовок перед выделенным объектом будет содержать размер выделения, который будет включать Bar
элемент данных.
2) Что ты имеешь в виду? Если конструктор по умолчанию создается пользователем, тогда зачем компилятору генерировать конструктор по умолчанию?
3) Bar
освобождается, потому что это является частью одного распределения Foo
,
4) Вам нужно будет изменить структуру бухгалтерского учета, которая окружает ваше распределение вручную. Это заставит стандартный менеджер памяти думать, что ваше распределение меньше, чем есть. Это может привести к неопределенному поведению и, возможно, вызвать сбой.
Все ваши вопросы действительно показывают, что вы понятия не имеете, что new
или же delete
делают. Я предлагаю прочитать о том, как построить простой менеджер памяти C ++.
Ну, вы можете перегрузить delete
Оператор ничего не делает, но это будет стрелять себе в ногу действительно очень плохо.
Я думаю, если бы вы действительно хотели, чтобы оператор удаления вызывал своего рода диспетчер памяти с указателем на себя вместо освобождения памяти, как часть шаблона пула или чего-то в этом роде. Этот менеджер также будет отвечать за уборку беспорядка в конце концов. но стоит ли это того?
Изменить: Извините, я не читал «не указатель» часть, я думаю, это не будет работать тогда.
Как насчет использования ссылки, которая инициализируется с новым ключевым словом?
AKA:
class Foo
{
private:
Bar& bar;
public:
Foo() : bar(*new Bar())
{ }
};
Я думаю, что это будет работать 🙂
1) это поведение является общим для всех членов данных — они включены в класс, поэтому существуют везде, где создается экземпляр класса. (Сами члены-указатели находятся в классе, даже если они отслеживают данные, на которые указывают указатели, в отдельной части кучи.) С точки зрения терминологии, вы можете сказать, что они «хранятся по значению», используя объектно-ориентированную «композицию» как отличную. из указанных или ссылочных данных.
2) У членов данных есть свои собственные конструкторы, которые запускаются перед телом конструктора класса. Вы можете предоставить аргументы конструкторам-членам данных, используя список инициализаторов ala Class() : data_member(value) { }
, Позже деструктор по умолчанию для класса запускается перед деструктором по умолчанию для членов данных — поэтому наличие пустого деструктора не влияет на уничтожение членов данных.
3) Деструктор запускается по умолчанию, и после того, как все члены данных и базы класса уничтожены, память освобождается. Для переменной free-store / heap все, что вызывается delete
,
4) Утечка памяти — это объект, который больше не используется программой, но не был и не будет уничтожен и освобожден. Единственными объектами, для которых автоматическое уничтожение / освобождение не выполняется, являются выделенные объекты свободного хранения / кучи, которые могут быть созданы только с использованием new
или же malloc
/realloc
(или функции, которые вызывают это, например, strdup
). Так что — вы должны использовать указатели (вы можете хранить ссылки аля *new X
но это все еще имеет дело с указателем на мгновение.