С++ Выделение памяти в куче и стеке?

Исходя из фона Java, я все еще немного запутался в распределении памяти в C++. Я почти уверен, что первые два утверждения верны:

void method() {
    Foo foo;    // allocates foo on the stack, and the memory is freed
                // when the method exits
}

void method2() {
    Foo *foo = new Foo();   // allocates foo on the heap
    delete foo;             // frees the memory used by foo
}

Но как насчет чего-то подобного?

void method3() {
    Foo foo = *new Foo();   // allocates foo on the heap, and then copies it to the stack?
                            // when the method exits, the stack memory is freed, but the heap memory isn't?
}

Скажем, я добавил foo в глобальный массив внутри method3(). Если бы я попытался получить доступ к одному из элементов данных foo после выхода из метода, сработало бы это? И method3() склонен к утечкам памяти?

Заранее спасибо.


person nebulabrot    schedule 24.02.2013    source источник
comment
Foo foo(); на самом деле ничего не выделяет. Он объявляет функцию.   -  person chris    schedule 24.02.2013


Ответы (1)


Foo foo(); 

Объявляет функцию с именем foo, которая возвращает объект Foo и не принимает никаких аргументов. Он известен как самый неприятный синтаксический анализ в C++. Вы, вероятно, имели в виду:

Foo foo; 

Он создает объект foo локально/автоматически. Объект автоматически освобождается после того, как область { }, в которой он объявлен, заканчивается.


Foo *foo = new Foo();   // allocates foo on the heap
delete foo;

Это правда, объект в свободном хранилище, на который указывает foo, освобождается после вызова delete. Утечек памяти нет.


 Foo foo = *new Foo(); 

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

person Alok Save    schedule 24.02.2013
comment
Я имел в виду Foo foo() для вызова конструктора без аргументов для класса Foo. Но вы правы, я изменю это в вопросе, чтобы избежать путаницы. - person nebulabrot; 24.02.2013
comment
@nebulabrot: Foo foo; делает это, а не Foo foo(); - person Alok Save; 24.02.2013
comment
Почему поведение undefined, если в деструкторе Foo присутствуют побочные эффекты? Я могу придумать пару примеров со сложным Foo, где он работал бы просто отлично, даже без утечки памяти! - person CygnusX1; 24.02.2013
comment
@CygnusX1: потому что так сказано в стандарте C++. - person Alok Save; 24.02.2013
comment
@Alok Сохранить: сказать, что так говорит стандарт, - самый бесполезный ответ. В какой строке стандарта так сказано? Вы уверены, что для каждого определения Foo вы столкнетесь с этой стандартной проблемой? - person CygnusX1; 24.02.2013
comment
Я сам ответил на него, посетив: stackoverflow.com/questions/9920973/ - person CygnusX1; 24.02.2013
comment
@CygnusX1: Вы можете придумать множество сценариев не является веской причиной для того, чтобы я вам что-то доказывал. И если бы вы приложили усилия для поиска раньше, вы бы избавили себя от разговоров, а меня от этого комментария. - person Alok Save; 24.02.2013
comment
Я мог бы полностью опустить утверждение о количестве сценариев и все же задать совершенно правильный вопрос о том, какой элемент стандарта приводит к неопределенному поведению. К сожалению, вы не были вынуждены отвечать на него, но я нашел его сам :) Что касается конкретного примера сценария: вышеприведенный код будет полностью в порядке, если конструктор Foo имеет побочный эффект регистрации в некотором глобальном наборе созданных объектов (и деструктор - снятие с учета). Такое простое управление предотвратило бы любую утечку памяти Foo в приведенных выше примерах. Другой пример может включать перегруженный оператор new для Foo... - person CygnusX1; 24.02.2013
comment
@AlokSave: спасибо, сэр. Есть ли способ предотвратить утечку памяти, когда я пишу как Foo f=*new Foo(); ? - person Destructor; 20.03.2015
comment
@meet: Нет, потому что для освобождения памяти вам нужен начальный адрес этого блока памяти. Вы вызываете delete для указателя, который указывает на этот блок памяти, но как только вы выполняете этот оператор, вы теряете этот начальный адрес. - person Alok Save; 21.03.2015
comment
@AlokSave У Foo &foo = *new Foo(); есть утечка памяти? - person Rix; 29.04.2015
comment
@Rix: Да, потому что вы теряете адрес, указывающий на динамическую память. - person Alok Save; 29.04.2015