Когда удалять [] указатель c ++? - PullRequest
0 голосов
/ 20 июня 2011

Я некоторое время играл с c ++, и, исходя из Java, одним из самых запутанных аспектов для меня является управление памятью. Например, допустим, у меня есть метод, и в этом методе я объявляю указатель на объект, я хочу установить этот указатель на атрибут другого объекта, используя метод get:

SubObject *mySubObject = anotherObject.getSubObject();

Мой вопрос: что происходит с этим указателем, когда метод заканчивается? я должен использовать следующее до его окончания?

delete mySubObject;

Что если я не удалю это? Останется ли она до конца всей программы?

Я пробовал поискать учебники по основному управлению памятью для c ++, но я обычно нахожу более продвинутые вещи, которые могут возникнуть у меня, любые рефералы будут оценены.

Ответы [ 9 ]

9 голосов
/ 20 июня 2011

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

3 голосов
/ 20 июня 2011

Чтобы ответить на вопрос в заголовке вашего поста, вы должны использовать delete[] тогда и только тогда, когда вы выделили память с new[]. Вы должны использовать delete тогда и только тогда, когда вы использовали new для выделения памяти.

int *array = new int[10];
int *ptr = new int;
...
delete[] array;
delete ptr;

Чтобы ответить на ваш пост, вы должны спросить себя, когда ваш код выделяет память. Фактически, вы должны думать о памяти как о ресурсе, таком как дескриптор файла или сетевое соединение. Каждый раз, когда вы открываете файл в C ++ или Java, после этого вы должны закрыть файлы. Аналогично, каждый раз, когда вы выделяете память в C ++, вы должны ее освободить. Сложный вопрос, когда вы должны освободить память. Так же как и метод

anotherObject.getSubObject();

вернуть указатель на вновь выделенный объект? Чьей задачей является освобождение памяти, на которую указывает указатель, возвращенный в вышеуказанном методе?

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

Если вы новичок в C ++ из Java, вам определенно следует попробовать ссылки , когда это возможно, и проверить интеллектуальных указателей . Хорошая особенность интеллектуальных указателей в том, что они обеспечивают автоматическое управление памятью (вам не нужно беспокоиться об удалении после того, как вы new отредактировали объект).

3 голосов
/ 20 июня 2011

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

Как правило, delete то, что у вас есть new 'd.Конечно, это сильно зависит от схемы программирования.

1 голос
/ 20 июня 2011

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

Изучите основы, а затем вы сможете вернуться к этим "продвинутым" предметам.

1 голос
/ 20 июня 2011

Чтобы ответить на вопрос в теме: В C ++ вы используете delete [], чтобы удалить массив, выделенный с помощью new []. То есть:

int *a = new int[10];  // Allocate 10 ints and save ptr in a.
for (int i=0; i<10; i++) {
    a[i] = 0;    // Initialize all elements to zero.
}
delete [] a; // Free memory allocated for the a array.

Как Густаво правильно указывает, причина [] в вызове удаления состоит в том, чтобы убедиться, что деструктор вызывается в каждом из элементов массива.

0 голосов
/ 20 июня 2011

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

SubObject *mySubObject = anotherObject.getSubObject();
delete mySubObject;

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

0 голосов
/ 20 июня 2011

В C ++ вы должны сами управлять распределением памяти, нет сборки мусора, которую вы забыли очистить, как в java / C #, и в любом другом современном языке.Если вы теряете след памяти, в лучшем случае она просочилась, в худшем случае вы продолжаете использовать ее, а что-то еще делает.Это трудная проблема для решения, очень немногие, если таковые вообще имеются, программисты C ++ понимают это правильно, поэтому для обхода этих проблем в C ++ выполняются умные указатели и другие сложные эзотерические приемы.@yi_H - это правильно, разберитесь с основами базового распределения памяти, чтобы вы знали, почему умные указатели являются такой хорошей идеей.

Без умных указателей, в то время как некоторые из приведенных выше ответов ускользнули от него "владение "является наиболее важной вещью, чтобы понять.Всякий раз, когда у вас есть указатель на блок памяти, вы должны знать, кому он принадлежит.Если вы им владеете, вы должны освободить его, прежде чем он выйдет за рамки или будет потерян.Если вы даете кому-то еще копию этого документа, убедитесь, что вы определили, кому он принадлежит, и когда владелец может / будет / должен освободить его.Если вы не можете сделать это, вы находитесь в шланге.Как правило, библиотеки C ++, как известно, плохо документируют это, поэтому при отсутствии четкой информации предположим, что она вам не принадлежит (не удаляйте ее и, возможно, не создайте утечку памяти), предпочитая ее удалять и создавать трудно обнаруживаемые дефекты.,Используйте Valgrind, чтобы найти утечки памяти в работающей программе.

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

т.е. ограничивает использование ключевого слова "new".

0 голосов
/ 20 июня 2011

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

Должен ли абонент или вызываемый абонент отвечать за управление памятью, если вы используете бесплатное хранилище ?Если другой человек вызывает функцию-член, теперь у вас есть висячий указатель .А что делать, если вызываемый абонент использует RAII ?

Поскольку вы учитесь (спасибо за это), попробуйте сначала изучить основы управления памятью.Если у вас есть базовые знания о памяти, вам будет удобнее работать с C ++ и с управлением памятью.

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

Удачи,

Армандо.

0 голосов
/ 20 июня 2011

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

При чтении этой документации / заголовка / источника вы должны искать ответ на вопрос "Распределяет ли getSubObject() память, которую вызывающая сторона должна удалить, или она просто возвращает указатель на существующий объект?" С таким именем, как getSubObject() Я бы ожидал, что последний случай. Я бы ожидал первого, если бы имя функции было createSubObject().

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