Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > освободится ли память?


Автор: ksili 16.3.2009, 08:23
освободится ли память в такой конструкции, если между new и delete произошло исключение и управление попало в catch?
Код

....
try
    {
    char* data = new char[len];
    ....
    delete [] data;
    }
catch(...)   
    {
    ....
    }

Автор: azesmcar 16.3.2009, 08:30
Цитата

освободится ли память в такой конструкции, если между new и delete произошло исключение и управление попало в catch?


нет, если будет брошено исключение, управление не дойдет до delete а сразу перейдет к блоку catch.

более того, если быть педантичным
Код

char* data = new char[len];


не гарантирует безопасность исключений. В С++ оператор new может генерировать исключения. Если использовать
Код

char* data = new(std::nothrow) char[10];


тогда оператор new вернет NULL. Но это так smile не думаю что это стоит проверять..так и так программа продолжать свою работу вряд ли сможет после того как уже не осталось памяти..хотя бывают и специфичные случаи.

Код

char* data = new char[len];
try
    {
    ....
    }
catch(...)   
    {
    ....
    }
delete [] data;

пиши так (если не собираешся делать rethrow в блоке catch

или
Код

try
{
   char* data = new char[len];
   try
       {
       ....
       }
   catch(...)   
       {
       ....
       }
   delete [] data;
} catch (std::bad_alloc& e) {
   //пытаемся красиво убить программу чтоб не мучалась  :smile 
}


хотя такие исключения как bad_alloc лучше перехватывать во входной точке.

Автор: ksili 16.3.2009, 09:06
azesmcar, спасибо за ответ. 

Т.к. у меня rethrow в блоке catch. Я сделал так:
Код

char* data;
try
    {
    data = new char[len];
    
    ....
    delete [] data;
    data = NULL;
    }
catch(...)   
    {
    ....
    if(data) delete [] data;
    throw CServerRequestException();
    }

Автор: azesmcar 16.3.2009, 09:11
Код

    if(data) delete [] data;


лишняя проверка. инициализируй
Код

char* data = 0;


и удаляй спокойно, в С++ удаление нулевых указателей - вполне нормально
Код

char* data = NULL;
try
    {
    data = new char[len];
    
    ....
    delete [] data;
    data = NULL;
    }
catch(...)   
    {
    ....
    delete [] data;
    throw CServerRequestException();
    }

Автор: Lazin 16.3.2009, 09:14
azesmcar, какой плохой совет smile 
во первых, не стоит использовать catch(...) без catch(const std::exception&) так как теряется контекст в котором произошла ошибка
во второых, лучше использовать идиому RAII, например использовать смарт поинтер

Код

try
{
    boost::scoped_array<char> data( new char[len]);
    ...
} 
catch (const std::exception& e)
{
    ....обработка исключения
}
catch (...)
{
    //аварийное завершение
    --запись в лог файл создание дампа приложения
   _exit(-1);
}

Автор: azesmcar 16.3.2009, 09:17
Цитата

azesmcar, какой плохой совет smile 
во первых, не стоит использовать catch(...) без catch(const std::exception&) так как теряется контекст в котором произошла ошибка
во второых, лучше использовать идиому RAII, например использовать смарт поинтер


во первых
catch(...) писал не я, и я не думал что тут имеется ввиду перехват всех исключений. Человек чтобы не писать все, просто написал три точки.
во вторых
Цитата

во второых, лучше использовать идиому RAII, например использовать смарт поинтер

есть множество решений. А бы не стал использовать смарт поинтер, так как - стандартно такого смарт поинтера в С++ нет, а писать его для того чтобы не писать один лишний delete я бы тоже не стал.

Добавлено через 1 минуту и 37 секунд
и причем тут буст??? мы говорим о С++? в С++ нет такого класса как
Цитата

boost::scoped_array<char> data( new char[len]);


Добавлено через 3 минуты и 30 секунд
а вообще catch(...) не хорошо. Это можно поставить как дополнительную проверку во входной точке после
catch (std::exception& e)

Автор: Lazin 16.3.2009, 09:21
Цитата(azesmcar @  16.3.2009,  09:17 Найти цитируемый пост)
есть множество решений. А бы не стал использовать смарт поинтер, так как - стандартно такого смарт поинтера в С++ нет, а писать его для того чтобы не писать один лишний delete я бы тоже не ста

scoped_ptr в TR1
к тому-же, писать delete вручную можно, но это приводит к туче boilerplate кода

Автор: azesmcar 16.3.2009, 09:22
Цитата

scoped_ptr в TR1


нет такого класса.  smile

Добавлено через 2 минуты и 12 секунд
Цитата

к тому-же, писать delete вручную можно, но это приводит к туче boilerplate кода 


зависит от того сколько раз придется это писать...конкретно в примере недостаточно информации чтобы посоветовать использовать smart pointer (по моему)

Автор: Lazin 16.3.2009, 09:28
действительно нет, зато есть в TR2 и в boost, в общем это не оправдание)

Автор: ksili 16.3.2009, 09:34
Я ищу и исправляю места, где могли бы быть утечки, в большом проекте, написанном не мной. Так что переписывать на smart pointer'ы я не буду. Ограничусь тем, что здесь написал и добавлением логгирования в catch(..)       
там действительно троеточие!

Автор: azesmcar 16.3.2009, 09:34
Цитата

действительно нет, зато есть в TR2 и в boost, в общем это не оправдание) 


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

Добавлено через 1 минуту и 26 секунд
Цитата

Я ищу и исправляю места, где могли бы быть утечки, в большом проекте, написанном не мной. Так что переписывать на smart pointer'ы я не буду. Ограничусь тем, что здесь написал и добавлением логгирования в catch(..)       


Bounds Checker пробовал?

Автор: mes 16.3.2009, 09:42
а чем std::auto_ptr для текущего примера тс не подходит ?

Автор: azesmcar 16.3.2009, 09:43
Цитата

а чем std::auto_ptr для текущего примера тс не подходит ? 


auto_ptr использует оператор delete а не delete []
Код

    ~auto_ptr()
        {    // destroy the object
        if (_Myptr != 0)
            delete _Myptr;
        }

Автор: Lazin 16.3.2009, 09:46
по твоему писать 
Код

try
{
   data = new char[len];
   ...
   delete data;
   data = 0;
}
catch(...)
{
   if (data) delete data;
   data = 0;
}

есть хорошо?
намного чище на мой взгляд
Код

try
{
    boost::scoped_array data(new char[len]);
}
catch(...)
{
   //здесь только обработка ошибки, cleanup происходит автоматичксски
}

ну а если у тебя в ф-ии создаются динамчески несколько объектов?
Цитата(azesmcar @  16.3.2009,  09:34 Найти цитируемый пост)
Если речь идет о С++ - тогда решаем проблему средствами С++, меня лично не устроил бы ответ "скачай буст и используй там один класс". Я не собираюсь качать буст ради одного класса который я буду использовать один раз в своей программе.

boost smart_ptr - header only библиотека, и ничего за собой не тянет, к тому-же я не думаю что ты сможешь написать свой смарт поинтер, аналогичный по реализации boost::shared_ptr =)

Цитата(azesmcar @  16.3.2009,  09:34 Найти цитируемый пост)
кому??? с чего ты взял что я оправдываюсь и вообще мне это надо? и перед кем?

спокойно, дышим глубже ))

Автор: azesmcar 16.3.2009, 09:56
Цитата

есть хорошо?


речь не о том - хорошо это или плохо. а о том что вопрос не был
Цитата

как сделать этот код лучше


а о том что вопрос был
Цитата

освободится ли память в такой конструкции, если между new и delete произошло исключение и управление попало в catch?


я лишь отвечал как сделать так чтобы не было утечки памяти, никто не спрашивал хорошо ли писать catch(...). 
Цитата

намного чище на мой взгляд


я не спорю что это так. Но, к коду добавляется дополнительный файл, в итоге мы получаем где-то 50 строк в отдельном файле, и избавляемся от 3х строк в одном. Мне кажется что смысл использования смарт поинтера в данной задаче определяется множеством факторов о которых нам не известно, поэтому сказать однозначно - которое решение лучше я не могу. Я предложил одно, ты предлагай другое..а уж тот кому виден весь код решит которое из них для него более приемлемо.

Цитата

спокойно, дышим глубже )) 


я спокоен как слон. Просто не люблю слова оправдания - я никогда и ни перед кем не оправдывался и не собираюсь этого делать, если я не прав - извинюсь, если меня неверно поняли - обясню еще раз..но не буду оправдыватся..

Автор: ksili 16.3.2009, 10:03
Цитата(Lazin @ 16.3.2009,  13:46)
по твоему писать 
Код

try
{
   data = new char[len];
   ...
   delete data;
   data = 0;
}
catch(...)
{
   if (data) delete data;
   data = 0;
}

есть хорошо?

В смысле "хорошо"?
 
мне надо чтобы не было утечки памяти. И желательно чтобы вносить минимум изменений в исходный код.

Автор: vinter 16.3.2009, 10:32
Цитата(ksili @  16.3.2009,  11:03 Найти цитируемый пост)
И желательно чтобы вносить минимум изменений в исходный код.

лучше слушай Lazin'а, изменения со smart pointers, будут минимально. Но ты напишешь чистый код и избавишь потомков(себя?) от проблем в будущем. 

Автор: maxim1000 16.3.2009, 19:54
а может, банальный std::vector? smile

Автор: Lazin 16.3.2009, 21:16
Цитата(maxim1000 @  16.3.2009,  19:54 Найти цитируемый пост)
а может, банальный std::vector?

в данном случае это оптимальный вариант smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)