Что происходит, когда память выделяется с помощью функции? - PullRequest
2 голосов
/ 03 мая 2019

Когда вы возвращаете вновь распределенную переменную через функцию, копия создается и передается, а оригинал автоматически удаляется?

Я предполагаю, что утечки памяти нет

#include <iostream>

using namespace std;

int* allocater()
{

    int* x = new int(1);
    return x; 

    // what happens to the memory allocated to x ?
}


int main()
{


int* a = allocater();
int* b = allocater();


cout<<*a<<"  "<<*b;

delete a;
delete b;

// all memory allocated has been deleted?

}

вывод соответствует ожидаемому.

Ответы [ 5 ]

5 голосов
/ 03 мая 2019

Когда вы возвращаете вновь распределенную переменную

Объекты с динамическим хранением не являются переменными.

В функции есть переменная.Он называется x.Тип переменной x равен int*, т. Е. Это указатель на целое число.

- копия сделана и передана, а оригинал удален автоматически?

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

Объекты с динамическим хранилищем (тип которых int в вашей программе) не уничтожаются автоматически.Они должны быть освобождены с выражением delete.

1 голос
/ 06 мая 2019

Всякий раз, когда память выделяется таким образом, она резервируется в «Куче». Это область памяти, выделенная вашей программе операционной системой. Используя функции выделения в C ++, например: new() или malloc() (есть и другие), непрерывный блок этой кучи зарезервирован, и адрес его (указатель) возвращается вызывающему коду.

Так в вашей функции:

int *allocater()
{
    int *x = new int(1);
    return x; 
}

Зарезервирован один фрагмент памяти целого размера (вероятно, 4-8 байт), и возвращается адрес этой памяти. Этот адрес является просто числом, когда число интерпретируется как место в памяти, оно называется указателем, но все равно это просто число.

Таким образом, когда ваша функция возвращается, память все еще выделяется в куче. Если ваша программа забывает этот номер, эта память «вытекла» - ваша программа не может отменить выделение с помощью delete(), delete[]() или free(), потому что у вас нет номера, чтобы указать функции перераспределения, где бесплатно.

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

0 голосов
/ 04 мая 2019

Большое спасибо за ваши очень информативные ответы и отзывы, действительно помогли прояснить ситуацию, использование указателей похоже на игру в передачу посылки!

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

Большое спасибо

0 голосов
/ 03 мая 2019

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

Однако иногда вам нужно распределять память динамически.В этом случае мы можем использовать new и delete, чтобы явно выделить и удалить память.Однако из C ++ 11 введены умные указатели, которые являются просто оберткой вокруг необработанного указателя.Это помогает в управлении временем жизни объектов.

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

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

Итак, в вашем коде x является локальной переменной, и как только функция вернется.x уничтожен, но не та память, на которую он указывает.

0 голосов
/ 03 мая 2019

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

В C ++ 11 (или более ранних auto_ptr -s) были введены указатели RAII: unique_ptr, shared_ptr и т. Д. Так что есливы используете их:

int* allocater()
{
    auto x = std::make_unique<int>(5);
    return x.get();  // getting raw ptr
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...