Изменение указателя динамически размещаемого массива

Когда мы объявляем что-то динамически, как это

int *ptr = new int [100];

а затем изменить адрес указателя (т.е. указать его на что-то другое)

int pointer[5] = {1,2,1,3,1,};
ptr = pointer ; 

что теперь происходит с той памятью, которая содержит 100 целых чисел?

есть ли способ вернуть контроль над этой памятью? и если нет, то приводит ли это к утечке памяти?

3 ответа

Решение

что теперь происходит с той памятью, которая содержит 100 целых чисел?

Это "утечка", потому что вы потеряли единственную ручку, которая у вас была.

есть ли способ вернуть контроль над этой памятью?

Нет, если только вы не позаботитесь о создании другого дескриптора перед повторным назначением ptr,

int* ptr = new int[100];
int* ptr2 = ptr;
...
ptr = pointer;
delete [] ptr2;

В реальном коде вы не будете полагаться на необработанные указатели на выделенную память, а будете использовать тот тип RAII, который лучше всего подходит для вашей проблемы (например, std::vector, std::unique_ptr так далее.)

Любой блок памяти, выделенный с new недоступен, пока не будет выпущен, либо соответствующим delete или когда процесс, в котором была выделена память, завершается.

Распределитель памяти фактически не имеет ни малейшего представления о том, какие ссылки вы храните для выделенных объектов. Он просто позволяет вам освободить соответствующие блоки памяти, если вам удастся предоставить действительные адреса.
Как вы отслеживаете эти адреса, полностью зависит от вас.

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

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

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

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

В образце, который вы даете, ptr это единственный указатель, который ссылается на сотню int создано new int [100] (т.е. указывает на первый элемент).

Изменение значения ptr не влияет на сотню int, Это означает, что ptr больше не содержит адрес первого элемента.

Практически, после назначения ptr = pointerвыделенная память считается утечкой - она ​​была выделена, в стандарте C++ нет способа получить к ней доступ, и в стандарте C++ нет возможности ее освободить (например, сделать доступной ее память для перераспределения в другой). new выражение).

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

На практике было бы лучше использовать стандартный контейнер (например, std::vector<int>) и не используйте новое выражение в вашем коде. Таким образом, содержимое контейнера доступно, пока контейнер существует (и перестает существовать, если это касается вашей программы, когда контейнер существует).

Другие вопросы по тегам