Проблема утечки памяти; удаление указателя - PullRequest
2 голосов
/ 25 февраля 2011

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

Итак, другими словами, если я delete указатель, значит ли этобольше не существует?Или оно есть, но не указывает на то, где оно было?

Ответы [ 6 ]

6 голосов
/ 25 февраля 2011

Синтаксис delete немного вводит в заблуждение. Когда ты пишешь

T* ptr = /* ... */
delete ptr;

Вы не удаляете переменную ptr. Вместо этого вы удаляете объект, на который указывает ptr. Значение ptr не изменяется и оно по-прежнему указывает на то место, которое использовалось ранее, поэтому вы должны быть уверены, что не разыменовываете его без предварительной переназначения.

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

Одна из техник, которую используют многие программисты на C ++ для упрощения логики освобождения памяти, - это использование интеллектуальных указателей , объектов, которые перегружают операторы, необходимые для имитации указателя, и имеют собственный код, который выполняется автоматически, чтобы помочь следить за ресурсами. Например, новый стандарт C ++ 0x предоставит для этой цели типы shared_ptr и unique_ptr. shared_ptr действует как обычный указатель, за исключением того, что он отслеживает, сколько shared_ptr есть на ресурс. Когда последний shared_ptr ресурса изменяется, куда он указывает (либо переназначаясь, либо уничтожаясь), он освобождает ресурс. Например:

{
    shared_ptr<int> myPtr(new int);
    *myPtr = 137;
    {
       shared_ptr<int> myOtherPtr = myPtr;
       *myPtr = 42;
    }
}

Обратите внимание, что нигде в этом коде нет вызова на delete для сопоставления с вызовом new! Это потому, что shared_ptr достаточно умен, чтобы заметить, когда последний указатель перестает указывать на ресурс.

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

1 голос
/ 25 февраля 2011

Чтобы ответить на ваш вопрос напрямую, он задавался ранее.delete удалит то, на что указывает ваш указатель, но Бьярн Страуструп предположил, что на значение самого указателя больше нельзя полагаться, особенно если это l-значение.Однако это не влияет на возможность переназначения, так что это будет правильно:

for( p = first; p != last; ++p )
{
   delete p;
}

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

Управление памятью в C ++ лучше всего выполнять с помощью метода RAII, «получение ресурсов является инициализацией».

На самом деле это означает, что во время выделения ресурса вы сразу же заботитесь о его времени жизни, т.е.вы «управляете» им, помещая его в какой-то объект, который удалит его для вас, когда он больше не нужен.

shared_ptr - это метод, обычно используемый, когда ресурс будет использоваться во многих местах, а вы не знаете, для чего он нужен.определенный, который последним «освободит» его, т. е. больше не требует его.

shared_ptr часто используется в других местах просто из-за его семантики, то есть вы можете скопировать и назначить их достаточно легко.

Существуют и другие умные указатели управления памятью, в частности std :: auto_ptr, которые будут заменены уникальными_ptr, и есть также scoped_ptr.Слабый_птр - это методология, позволяющая получить shared_ptr, если он где-то существует, но не содержит ссылки самостоятельно.Вы вызываете «lock ()», который дает вам shared_ptr для памяти или NULL, если все текущие общие указатели исчезли.

Для массивов вы обычно не используете умный указатель, а просто используете vector.

Для строк вы обычно используете класс string, а не думаете о нем как о символе char.

1 голос
/ 25 февраля 2011

Короче говоря, вы не «удаляете указатель», вы удаляете все, на что указывает указатель.

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

Кроме того, указатель может указывать на то, что изначально не было выделено «новым», например статическийпеременная, объект в стеке или в середине другого объекта.Во всех этих случаях вам не разрешается удалять все, на что указывает указатель.

Как правило, при разработке приложения вы (да, вы) должны решить, какой части приложения принадлежит конкретный объект.Он и только он должен удалять объекты, когда это сделано.

1 голос
/ 25 февраля 2011

Когда вы вызываете delete, вы помечаете память, на которую указывает указатель, как свободную - куча становится ее владельцем и может повторно использовать, вот и все, сам указатель обычно не изменяется .

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

1 голос
/ 25 февраля 2011

xtofl, хотя и смешной, но немного правильный.

Если вы «новый» адрес памяти, то вы должны удалить его, в противном случае оставьте его в покое. Может быть, вы слишком много думаете об этом, но вы думаете об этом, как это. Да, память всегда есть, но если вы поставите забор вокруг него, вам нужно снять его, или никто другой не сможет это сделать.

1 голос
/ 25 февраля 2011

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

...