2012-03-03 3 views
1

У меня есть этот вопрос относительно выделения и освобождения памяти в C++. Вот ситуация: У меня есть метод Foo, который выделяет память, а затем возвращает этот объект:Освобождение памяти C++ после возврата

Object foo() { 
    Object *a = new Object(); 
    // Do something with this object... 
    return *a; 
} 

и другой метод, который использует этот возвращенный объект:

void bar() { 
    Object a = foo(); 
    // Do something.. 
} 

И мой вопрос, в в какой точке я должен освободить память, которую я выделил? Когда я вернусь из метода foo, панель методов получает копию этого объекта в стеке или получает доступ к этому одному объекту где-то в памяти?

Спасибо! Bart

+2

Вы не должны выделять память через новое вообще здесь – PlasmaHH

+0

@PlasmaHH - почему бы и нет? –

+0

, потому что вы не возвращаете указатель, а копию объекта. – P3trus

ответ

5

Вы не можете освободить этот объект. Он потерян. Это утечка памяти. Вы никогда не должны (динамически) выделять его в первую очередь. Ваш код должен был выглядеть так:

Object foo() { 
    Object a; 
    // Do something with this object... 
    return a; 
} 

Когда я вернулся из метода Foo, делает бар способ получить копию , что объект на его стеке, или оно получает доступ к этому одному объекту где-то в памяти?

Это копия все еще существующего недоступного объекта.

+0

Разве это не выделяет память в стеке? – user1096294

+0

@ user1096294: Да, это так. –

+0

@ user1096294: На самом деле, я должен исправить себя до того, как меня соберет адвокат языка. Объект получает выделенную автоматическую продолжительность хранения, что на практике обычно означает, что он получает выделение в стеке. –

0

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

+0

Вы никогда не должны удалять ссылку. И вы никогда не сможете сказать, следует ли удалять указатель (без чтения документации), и, следовательно, это очень подвержено ошибкам. В результате мы не передаем объекты указателем, когда вопрос о собственности находится под вопросом в C++ (для этого было бы очень похоже на C). Вместо этого мы передаем интеллектуальные указатели, которые определяют семантику собственности динамически выделенного объекта, или мы возвращаемся по значению (что, вероятно, является лучшим решением). Поскольку RVO и NRVO не будут стоить стоимости, ничего не копируют. –

1

Выделение памяти с помощью new говорит компилятору: «Не беспокойтесь, я знаю, что я делаю: этот объект будет контролироваться мной». Это означает, что компилятор, действительно, не будет беспокоиться об этом, и вы ставите его на себя. Лучшее решение: не делайте этого, если вы действительно не знаете, что делаете. Заметьте, что я уверен, что знаю, что делаю, и все же я обычно не использую new, потому что нет необходимости!

В вашем примере, вы хотите использовать

Object foo() { 
    Object a; 
    // do something 
    return a; 
} 

Концептуально объект создается на стеке и скопировать, когда он возвращается. После завершения копирования локальный объект будет уничтожен. На практике это редко происходит на самом деле: поскольку локальный объект уничтожается сразу после его копирования, компилятору предоставляется свобода делать то, что вы обычно хотите, а именно: объект a не копируется и не уничтожается, а фактически возвращается напрямую , Однако это должно дать тот же результат (если это не так, ваш класс где-то сломан).

+0

Вы хотите сказать, что мы возвращаем объект из стека метода? Разве это не означает, что объект будет переписан в какой-то момент? – user1096294

+1

Когда компилятор возвращает копию, он знает, что он делает, и не перезаписывает его в течение своего жизненного цикла. Обратите внимание, что объект, который вы вернули из своей функции, является копией объекта, который вы указали с помощью 'new' (и, вероятно, объект' new'ed просочился, если он не будет зарегистрирован где-нибудь, что будет заботиться об объекте). –

3

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

Object foo() { 
    Object a; 
    return a; 
} 

Если вам действительно нужен объект в куче, например,если это полиморфный объект и вы как раз возвращает указатель на базовый класс, это будет выглядеть как

Base* foo() { 
    Base *a = new Derived(); 
    return a; 
} 

Но этот код далек от хорошего. Это не исключение, которое может привести к утечке памяти. Поэтому вы почти всегда должны переносить новый с помощью умного указателя, такого как std :: unique_ptr (только C++ 11), std :: auto_ptr или boost :: shared_ptr.

std::unique_ptr<Base> foo() { 
    std::unique_ptr<Base> a(new Derived(); 
    return a; 
}