#c #pointers #malloc
#c #указатели #malloc
Вопрос:
Я работаю над рефакторингом устаревшего кода C с использованием C и делаю это по частям из-за большого объема кода, который нуждается в рефакторинге. Переработанный код C создает структуры LegacyCAttribute с помощью стратегий извлечения malloc и значений. Нерефакторированный код по-прежнему использует старые структуры LegacyCAttribute.
Если я возвращаю переменную стека в рамках стратегии get в вызывающий код, все в порядке. Но если я сделаю LegacyCAttribute* переменной-членом класса ValueStrategy, ядро вызывающего кода сбрасывается.
Этот код работает нормально:
class ValueStrategy {
public:
LegacyCAttribute* get();
};
LegacyCAttribute* ValueStrategy::get()
{
LegacyCAttribute* attr = malloc(sizeof(LegacyCAttribute));
// Build attr here by malloc'ing more memory for attr value lists and values etc.
return attr;
}
Это вызывает дамп ядра в вызывающем get, когда он пытается использовать указатель, возвращенный get:
class ValueStrategy {
public:
LegacyCAttribute* get();
LegacyCAttribute* m_attr;
};
LegacyCAttribute* ValueStrategy::get()
{
m_attr = malloc(sizeof(LegacyCAttribute));
// Build m_attr here by malloc'ing more memory for attr value lists and values etc.
return m_attr;
}
Я знаю, что m_attr исчезает, когда объект ValueStrategy уничтожается, но память, которая была выделена с помощью malloc(), на которую он указывает, не освобождается при этом уничтожении, поэтому я не понимаю, почему вызывающий код завершает работу с использованием указателя, возвращаемого вызовом get() во 2-м случае, ине 1-й.
Исправление — 2-я версия кода действительно работает — это был сброс ядра, потому что код был фактически:
LegacyCAttribute* ValueStrategy::get()
{
if (m_attr == NULL)
{
m_attr = malloc(sizeof(LegacyCAttribute));
// Build m_attr here by malloc'ing more memory for attr value lists and values etc.
}
return m_attr;
}
я не инициализировал m_attr равным NULL в параметре ValueStrategy ctor.
Спасибо всем, кто откликнулся, вы потрясающие! Извините за шум.
Комментарии:
1. Каково значение указателя m_attr при сбое? Не могли бы вы показать вызывающий код?
2. Аааа… Я снова просмотрел его, пытаясь предоставить больше информации, и понял, что я не инициализировал m_attr равным NULL в параметре ValueStrategy ctor, и поэтому код в get() не вызывал malloc, потому что m_attr не был NULL! Этот код действительно работает. Ого!!!!!
Ответ №1:
Классы в C по умолчанию копируются. Если они содержат указатели, копируются указатели, но не то, на что они указывают. Если деструктор одного из экземпляров класса затем вызывает delete
указатель (или free() ), он оставит другую копию с «висячим указателем», что впоследствии вызовет всевозможные головные боли.
Тем не менее, пожалуйста, предоставьте реальный код, сведенный к небольшому, но полному примеру. В частности LegacyCAttribute* attr = malloc(sizeof(LegacyCAttribute));
, не будет компилироваться как C , поскольку в нем отсутствует static_cast
. Ну, если LegacyCAttribute
на самом деле это псевдоним для void
, но полный пример покажет это. 🙂
Комментарии:
1. Спасибо, Ульрих, я обнаружил ошибку, когда пытался написать короткий пример программы, и это было не там, где я ожидал (см. Другие ответы на комментарии).