Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> освобождение памяти 
V
    Опции темы
CTapMex
Дата 15.1.2010, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Приветствую. 
тема вроде избитая, но вот нашел интересный момент.
исходные данные  - VC++ 2008 SP1

код такого содержания
Код

wchar_t *Name = null;
//тут у нас при наличии данных в реестре идет выделение памяти под Name  
int len=rGetValue(hPluginRegistry, 'name', Name);
if (len<=1)  
  Name = L"default";

далее некоторые действия с Name, не меняющие его содержимого
delete[] Name;



ошибка происходит в последней строчке, при выполнении выше  Name = L"default";
на сколько я понимаю , при компилировании строка помещается в область данных, и при условии len<=1 дается ссылка на эту область.
тут видимо и должна происходить ошибка, ведь память вроде как и не выделялась

но вот есть такой момент
запускаю этот код на WinXP SP3 хоть под отладчиком, хоть уже в релизе - все как часы работает. 
Но вот стоит запустить это на WinXp SP2  (не на всех компах срабатывает) , либо на Win7 (опять же через раз ) то выскакивает ошибка "Runtime Error! ...."
да и когда тестировал в отладчике на win7  ошибка не возникала, соберу релиз - появилась. пересоберу релиз без изменений - работает.

тут соответственно вопрос
мой код все таки некорректен?  или это уже ошибка компилятора/библиотек которые то корректно отрабатывают удаление памяти, то некорректно
PM MAIL   Вверх
artsb
Дата 15.1.2010, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Лично я считаю, что должно быть так:
Код

wchar_t *Name = NULL;

int len=rGetValue(hPluginRegistry, 'name', Name);
if (len<=1) {
  Name = new wchar_t[wcslen(L"default")];
  wcscpy(Name, L"default");
}

if(Name)
 delete [] Name;

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

Это сообщение отредактировал(а) artsb - 15.1.2010, 09:45


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



artsb
спасибо за пример, я предполагал по другом это решить. но у тебя решение лучше.

ну пару раз прокатило - но оно прокатывало то интересно как  то - на разных компах по разному. у себя на компе я ни разу как не пытался не мог заставить появится ошибке. 
а уж на win7 через раз. 
у меня стойкое впечатление, что эту ситуацию по разному обрабатывают разные версии ситемных библиотек. или компилятор
PM MAIL   Вверх
Dem_max
Дата 15.1.2010, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



Наверное код нужно подправить  smile 
Код

wchar_t *Name = NULL;
int MAX_LEN = 255;

Name = new wchar_t[MAX_LEN];

int len=rGetValue(hPluginRegistry, 'name', Name);
if (len<=1) {
  wcscpy(Name, L"default");
}

if(Name)
 delete [] Name;




--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Dem_max

в моем случае твой вариант не вариант.
в процедуре rGetValue идет чтение строкового значения из реестра. а оно может быть по размеру любым. по этому выделение памяти  идет по факту.
PM MAIL   Вверх
artsb
Дата 15.1.2010, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(CTapMex @  15.1.2010,  09:52 Найти цитируемый пост)
а уж на win7 через раз.

У меня ни разу не прокатило smile

По поводу вашего случая.
ИМХО в этом случае, компилер смотрит что строка константная и пихает её в ресурсы, а после этой операции:
Код

Name = L"default";

в Name хранится указатель на строку, которую вы не создавали. А потом вы пытаетесь её удалить  smile 
В этом случае, нужно убрать
Код

delete [] Name;

и должно работать. ИМХО

ЗЫ поправьте если что smile


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



artsb
все правильно говоришь. но вот работало у меня.
хотя я уже ни в чем не уверен. вечером еще раз проверю на win7
PM MAIL   Вверх
Dem_max
Дата 15.1.2010, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



Цитата(CTapMex @  15.1.2010,  10:20 Найти цитируемый пост)
в процедуре rGetValue

Значит в процедуре выделяется память ?


Цитата(artsb @  15.1.2010,  10:26 Найти цитируемый пост)
в Name хранится указатель на строку, которую вы не создавали. А потом вы пытаетесь её удалить   В этом случае, нужно убрать
ЗЫ поправьте если что

Все верно.
Для новичка эта вещь не очевидная, если он ее не поймет то дальше  можеть быть крах программы. И человек просто запарится искать свой косяк.



--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Цитата(Dem_max @ 15.1.2010,  13:28)
Цитата(CTapMex @  15.1.2010,  10:20 Найти цитируемый пост)
в процедуре rGetValue

Значит в процедуре выделяется память ?

да, в первом посте это указано


PM MAIL   Вверх
artsb
Дата 15.1.2010, 12:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



CTapMex, ну вы понимаете, что в функции не может выделиться память для Name? Вы передаёте нулевой указатель и все. Память выделяется под указатель, который является параметром функции. Т.е.
Код

int rGetValue(..., ..., wchar_t *ff) {
// здесь ff = NULL
ff = new wchar_t[5];
// Name не будет указывать туда же куда и ff
}


Это сообщение отредактировал(а) artsb - 15.1.2010, 12:18


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



ну, вы полезли уже глубоко. 
вот сама функция
Код

DWORD rGetValueSz(HKEY hReg, const wchar_t *name, wchar_t *&Data)
{
    DWORD i, Len=0;
    i=RegQueryValueExW(hReg, name, 0, NULL, NULL, &Len);
    if (i==ERROR_SUCCESS)
    {
        int l=Len / sizeof(wchar_t);
        Data=new wchar_t[l];
        i=RegQueryValueExW(hReg, name, 0, NULL, (PBYTE)Data, &Len);
        if (i==ERROR_SUCCESS)
        {
            return l;
        }
        else return 0;
    }
    else return 0;
};


PM MAIL   Вверх
artsb
Дата 15.1.2010, 12:36 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(CTapMex @  15.1.2010,  12:29 Найти цитируемый пост)
ну, вы полезли уже глубоко. 

Тем не менее в тему.


Цитата(CTapMex @  15.1.2010,  12:29 Найти цитируемый пост)
wchar_t *&Data

амперсанд здесь не нужен.

И вы нигде не освобождаете Data.

Добавлено @ 12:39
Пробуйте так:
Код

wchar_t *rGetValueSz(HKEY hReg, const wchar_t *name, DWORD &res)
{
    wchar_t *Data;
    DWORD i, Len=0;
    res = 0;
    i=RegQueryValueExW(hReg, name, 0, NULL, NULL, &Len);
    if (i==ERROR_SUCCESS)
    {
        int l=Len / sizeof(wchar_t);
        Data=new wchar_t[l];
        i=RegQueryValueExW(hReg, name, 0, NULL, (PBYTE)Data, &Len);
        if (i==ERROR_SUCCESS)
        {
            res = l;
            return Data;
        }
        else {
            delete [] Data;
            return NULL;
        }
    }
    else return NULL;
};


Добавлено @ 12:41
А юзать так:
Код

wchar_t *Name = null;

DWORD len;
Name = rGetValue(hPluginRegistry, 'name', &len);
if (len<=1)  
  Name = L"default"; // но тогда эта строка - бред ИМХО

if(Name)
 delete[] Name;


Это сообщение отредактировал(а) artsb - 15.1.2010, 13:07


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



Цитата(artsb @ 15.1.2010,  14:36)

амперсанд здесь не нужен.
И вы нигде не освобождаете Data.

 вот про удаление - да, не заметил. спасибо. 

Цитата(artsb @ 15.1.2010,  14:36)

Пробуйте так:

А юзать так:
Код

wchar_t *Name = null;

DWORD len;
Name = rGetValue(hPluginRegistry, 'name', &len);
if (len<=1)  
  Name = L"default"; // но тогда эта строка - бред ИМХО

delete[] Name;

да, так лучше будет . спасибо 
а про бред - твой самый первый вариант решения тут подойдет

Это сообщение отредактировал(а) CTapMex - 15.1.2010, 15:20
PM MAIL   Вверх
artsb
Дата 15.1.2010, 13:48 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Если вы проверяете удалось ли что-то получить после вызова rGetValue, то лучше так:
Код

wchar_t *Name = null;
DWORD len;
Name = rGetValue(hPluginRegistry, 'name', &len);
if (!Name) {
  Name = new wchar_t[wcslen(L"default")];
  wcscpy(Name, L"default");
}
// ...
if(Name)
 delete[] Name;

а от len можно вообще избавиться.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



еще раз спасибо 
PM MAIL   Вверх
17dufa
Дата 15.1.2010, 14:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 324
Регистрация: 2.3.2006

Репутация: 3
Всего: 5



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

CTapMex, если выделять динамически память - то прячьте ее в RAII (std::auto_ptr, boost::shared_ptr и тп) *Мейерс правило 13 из "55 советов"
PM MAIL   Вверх
artsb
Дата 15.1.2010, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(17dufa @  15.1.2010,  14:35 Найти цитируемый пост)
а почему собственно амперсант не нужен? он позволяет модифицировать Name из вызывающей функции и вызывающая функция уже и удаляет эту память. 

Так там и &, и * сразу.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
17dufa
Дата 15.1.2010, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 324
Регистрация: 2.3.2006

Репутация: 3
Всего: 5



artsb, и почему это Вас так пугает? именно это позволяет изменить Name в вызывающей функции и соответственно иметь в вызывающей функции доступ к считанному значению, а в последствии удалить память опять же в рамках вызывающей функции.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



17dufa
про RAII взял на заметку. сейчас переделывать все не резон. да и надо поизучать
PM MAIL   Вверх
artsb
Дата 15.1.2010, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



А вы понимаете, что * (указатели) и & (ссылки) это разные вещи? Зачем делать такую ядерную смесь? Удивительно, как оно вообще скомпилилось.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
17dufa
Дата 15.1.2010, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 324
Регистрация: 2.3.2006

Репутация: 3
Всего: 5



artsb, я-то понимаю, более того вполне понимаю что ссылка на указатель имеет право на жизнь согласно стандарту и компиляторам. зачем делать ядерную смесь - это кому какие предпочтения, кого-то двойные указатели пугают, Вас вот похоже ссылка на указатель в ступор вводит smile 
PM MAIL   Вверх
artsb
Дата 15.1.2010, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Всё. Я вас понял  smile 


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
CTapMex
Дата 15.1.2010, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 20.2.2007

Репутация: нет
Всего: нет



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

другой вопрос разумно ли так делать? а почему нет? не всегда есть возможность поменять функцию, как сделал ты выше. т.е. если надо передать 2 указателя и в них записать что надо
PM MAIL   Вверх
17dufa
Дата 15.1.2010, 15:40 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 324
Регистрация: 2.3.2006

Репутация: 3
Всего: 5



CTapMex, так делать можно и работать оно будет. а можно взять от указателя адрес и в функцию передать двойной указатель:
Код

....
char * name;
put(&name);
...
delete[] name;
...
char * put(char ** ptr)
{
   *ptr = new char[100];
   strcpy(*ptr, "some value");
   return *ptr;
}

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

по мне - разница чисто синтаксическая.
PM MAIL   Вверх
artsb
Дата 15.1.2010, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(CTapMex @  15.1.2010,  15:35 Найти цитируемый пост)
другой вопрос разумно ли так делать? а почему нет? не всегда есть возможность поменять функцию, как сделал ты выше. т.е. если надо передать 2 указателя и в них записать что надо 

Пользуйтесь. Как сказал 17dufa, всё будет работать. Я просто изначально не совсем понял что вы делали  smile 


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1162 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.