Может для кого-то это очевидно, но я раньше мучался этой проблемой.
Суть в том, что когда в функции создаются несколько обьектов, выделяется для них память.
И вдруг возникает какая либо неприятность (памяти не хватило, файла нет и т.п. )
Нужно корретно выйти из функции, осободив все ранее созданные обьекты.
По моему это не очень красивый и надежный метод. Елементарно можно забыть где-нибудь поставить free(..)
Много разных идей было как сделать "красивый" и надежный код.
И вот осенило — нужно вкусить "запретный плод" — goto
До этого свято веря, что все можно сделать и без него, даже елегантнее.
M>Я это написал, потому-что может это кому-нибудь будет полезным. M>Может кто-то предложит такой-же эффективный метод, но без goto?
M> M>А еще goto классно работает когда нужно быстро выйти из функции при этом что-то выполнив на последок
M>Главное не переуседствовать и не тыкать goto без везких оснований...
M>Истина всегда где-то посередине.
филосов
истина лежит в использовании, к примеру, std::auto_ptr
Здравствуйте, ssm, Вы писали:
ssm>истина лежит в использовании, к примеру, std::auto_ptr
Все он правильно говорит, это же С, а не С++, а форум у нас по С/С++, а не только по С++.
Другое дело, что ничего нового сказано не было, все и так на С этим пользуются :)))
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, ssm, Вы писали:
ssm>>истина лежит в использовании, к примеру, std::auto_ptr
J>Все он правильно говорит, это же С, а не С++, а форум у нас по С/С++, а не только по С++. J>Другое дело, что ничего нового сказано не было, все и так на С этим пользуются
оно то конечно, с одной стороны, — да, если судить по названию форума,
но с другой, если судить по описанию /*Программирование на C++. No VCL, no MFC, pure C++ only.*/ то скорее всего, что — нет
M>Нужно корретно выйти из функции, осободив все ранее созданные обьекты. <...> M>Елементарно можно забыть где-нибудь поставить free(..) M>Много разных идей было как сделать "красивый" и надежный код. И вот осенило — нужно вкусить "запретный плод" — goto
если говорить о C то можно использовать __try __finally
MSG* new_msg(..)
{
MSG* msg = NULL;
HEADER* header = NULL;
ADDR* to = NULL;
ADDR* from = NULL;
char* body = NULL;
__try
{
header = (HEADER*) malloc( sizeof(HEADER) );
if (header == NULL)
__leave;
...
to = (ADDR*)malloc( sizeof(ADDR) );
if (to == NULL)
__leave;
...
from = (ADDR*)malloc( sizeof(ADDR) );
if (from == NULL)
__leave;
...
msg = (ADDR*)malloc( sizeof(MSG) );
if (msg == NULL)
__leave;
...
}
__finally
{
if (body) free( body ); // !!!if (from) free( from ); // !!!if (to) free( to ); // !!!if (header) free( header ); // !!!
}
}
P.S. я не знаю, __try __finally (__except) стандарт С?
Re[3]: Выход из функции при ошибке
От:
Аноним
Дата:
26.12.02 11:30
Оценка:
Здравствуйте, jazzer, Вы писали:
J>Все он правильно говорит, это же С, а не С++, а форум у нас по С/С++, а не только по С++. J>Другое дело, что ничего нового сказано не было, все и так на С этим пользуются
Я даже C99 стандарт просмотрел — никаких try, finally — чего-то подобного.
Может плохо смотрел.
Может в других клонах чистого С кто видел ?
Здравствуйте, Аноним, Вы писали:
А>Я даже C99 стандарт просмотрел — никаких try, finally — чего-то подобного. А>Может плохо смотрел. А>Может в других клонах чистого С кто видел ?
__try — __finally вещь очень удобная, но в стандарте этого нет, т.к. это
Microsoft Specific —>
The try-finally statement is a Microsoft extension to the C and C++ languages that enables 32-bit target applications to guarantee execution of cleanup code when execution of a block of code is interrupted. Cleanup consists of such tasks as deallocating memory, closing files, and releasing file handles. The try-finally statement is especially useful for routines that have several places where a check is made for an error that could cause premature return from the routine.
For more information on structured exception handling in general, see Exception Handling Topics (SEH).
Гоуту не просто так в игнор записали. Если памяти не хватило, то уже
без разницы когда проверять выделена она или нет. Т.е. все проверки
после всех выделений памяти спасут программера от пользования этим
страшным оператором.
Здравствуйте, jazzer, Вы писали:
J>Другое дело, что ничего нового сказано не было, все и так на С этим пользуются
Я тоже так думал, но устаю видеть как программисты пишут такие конструкции.
Бывает, что дублируется по 10 строчек кода от условия к условию.
И это каким-то чудом проходит испекции кода
Здравствуйте, vav, Вы писали:
vav>А разве это не классический пример выгоды использования умных указателей?
Возможно. Я слабо представляю себе как их можно использовать?
Я говорю не только про выделение памяти, это может быть любой ресурс (файл, сокет и т.п.).
try
{
// здесь получаем ресурсы
ptr = new char[256];
}catch(...)// или конкретный тип исключения
{
if(ptr != null)delete ptr;
// Для других типов ресурсов аналогично
}
Можно также использовать в более сложных ситуациях ещё и __try{} __finaly( Разширения от МелкоСофта ), но это только в крайних случаях и должно быть соответственно оправдано, у меня по крайней мере таких потребностей не возникало.
try
{
// здесь получаем ресурсы
ptr = new char[256];
}catch(...)// или конкретный тип исключения
{
if(ptr != null)delete ptr;
// Для других типов ресурсов аналогично
}
А для CreateFile(..) или fopen(..) тоже будут генерироваться исключения?
Здравствуйте, menify, Вы писали:
M>Здравствуйте, vav, Вы писали:
vav>>А разве это не классический пример выгоды использования умных указателей? M>Возможно. Я слабо представляю себе как их можно использовать?
M>Я говорю не только про выделение памяти, это может быть любой ресурс (файл, сокет и т.п.).
Здравствуйте, menify, Вы писали:
M>Здравствуйте, Stoune:
M>
M>try
M>{
M> // здесь получаем ресурсы
M> ptr = new char[256];
M>}catch(...)// или конкретный тип исключения
M>{
M> if(ptr != null)delete ptr;
M>
Проверку на NULL можно убрать. M>
M>// Для других типов ресурсов аналогично
M>}
M>
M>А для CreateFile(..) или fopen(..) тоже будут генерироваться исключения? M>
Можно проверить код возврата и в случае ошибки сгенерировать исключение.
При частом использовании таких ресурсов лучше сделать класс-обертку, в конструкторе которого выделяется ресурс (открывается файл), а в деструкторе — освобождается.
Хорошая статья на тему Resource management.
Здравствуйте, menify, Вы писали:
M>Нужно корретно выйти из функции, осободив все ранее созданные обьекты.
Это велосипед но как иначе обяснить как это все работает.
template<class P_Type>
class T_Smart
{
P_Type* m_ptr;
//блокируем копирование
T_Smart(const T_Smart& obj);
T_Smart& operator=(const T_Smart& obj);
public:
//захватываем готовый указатель
//для вазова конструктора с параметрвми
//T_Smart<Foo> foo=new Foo(p1, p2, p3);
T_Smart(P_Type* ptr)
:m_ptr(ptr)
{}
//создает новай обьект
//конструктор по умолчанию
T_Smart()
:m_ptr(new P_Type)
{}
//разрушает обьект при выходе из области видимости
~T_Smart()
{
delete m_ptr;
}
//приведение к указателю на тип обьектаoperator P_Type*()
{
return m_ptr;
}
//обращение к мемберам обьекта
//foo->SomeFunc();
P_Type* operator->()
{
return m_ptr;
}
//Отцепляет обьект например для возвращения из функции
P_Type* Detach()
{
P_Type* t=m_ptr;
m_ptr=0;
return t;
}
};
Для других ресурсов аналогично.
Будут вопросы спрашивай.
... << RSDN@Home 1.0 beta 4 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, menify, Вы писали:
M>Здравствуйте, ssm, Вы писали:
M> ssm>>истина лежит в использовании, к примеру, std::auto_ptr M>Я плохо знаю C++, что такое std::auto_ptr? M>Как это будет выглядеть, хотя бы примерно?
это класс, который всасывает указателдь на что-нибудь (созданный при помощи new), а в деструкторе он его удаляет при помощи delete:
struct A
{
int i;
double j;
};
void f()
{
std::auto_ptr<A> ap(new A); // создали
ap->i = 7; // работаем, как с обычным указателем
ap->j = 3.14;
} // а здесь объект ap выходит из области видимости и удаляется,
// что приводит к вызову деструктора, а в нем вызовется delete.
// то же самое произойдет при return или возбуждении исключения.
а то, что delete не делает ничего, если ему подсунуть нулевой указатель, то вообще можно быть спокойным и не бояться, что при такой автоматической очистке произойдет что-то не то.
Здравствуйте, jazzer, Вы писали:
ssm>>>истина лежит в использовании, к примеру, std::auto_ptr
Я гдето слышал что изи этого оператора его в STL ные контейнеры совать нельзя
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, jazzer, Вы писали:
ssm>>>>истина лежит в использовании, к примеру, std::auto_ptr WH>Я гдето слышал что изи этого оператора его в STL ные контейнеры совать нельзя
так и есть, на самом деле комитет старается сделать все возможное, чтобы предотвратить использование auto_ptr в стандартных контейнерах, и именно для этого оператор присваивания и конструктор копирования принимают неконстантный объект
WH>Можно так но у ATL::CAdapt такой дурацкий интерфейс что проще написать свой врапер и не мучаться. WH>
проще,наверное, будет использование интелектуальных указателей с подсчетом ссылок, например boost::smart_ptr, а не изобретение велосипеда. но суть дела в том, что у auto_ptr свои задачи, с которыми он отлично справляется
Здравствуйте, ssm, Вы писали:
ssm>так и есть, на самом деле комитет старается сделать все возможное, чтобы предотвратить использование auto_ptr в стандартных контейнерах, и именно для этого оператор присваивания и конструктор копирования принимают неконстантный объект
прошу прощения, конечно же неконстантную ссылку на неконстантный объект:
auto_ptr нельзя использовать в контейнерах из-за того что при копировании\присваивании меняется ownership!
WH>Здравствуйте, jazzer, Вы писали:
ssm>>>>истина лежит в использовании, к примеру, std::auto_ptr WH>Я гдето слышал что изи этого оператора его в STL ные контейнеры совать нельзя WH>