Russian Qt Forum
Ноябрь 14, 2024, 20:41 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6 7   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Обработка ошибок без исключений и с помощью исключений  (Прочитано 50609 раз)
8Observer8
Гость
« Ответ #45 : Март 27, 2014, 08:58 »

С исключениями в C++ связано много ловушек. Одна из главных причин, по-моему, это совместимость с языком Си. Таких ловушек нет в C# и Java (а может они тоже есть, но их меньше). Чтобы избежать ловушек надо попробовать моделировать C# и Java.

Буду по мере познания выкладывать здесь примеры Улыбающийся

Пример. Ликвидация утечки памяти (из-за исключений) с помощью shared_ptr (или unique_ptr)

Вот пример плохого кода, в котором из-за исключения не освобождаются ресурсы и происходит утечка памяти. Пример из книги "Professional C++", глава 10, называется пример "StackUnwinding\BadCode". В этом примере команда delete str2; не выполняется из-за того, что функция funcTwo(); выбрасывает исключение и дело до освобождения ресурса не доходит:
Код
C++ (Qt)
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
 
void funcOne( ) throw (exception);
void funcTwo( ) throw (exception);
 
int main( ) {
   try {
       funcOne( );
   } catch ( const exception& e ) {
       cerr << "Exception caught!" << endl;
       return 1;
   }
 
   return 0;
}
 
void funcOne( ) throw (exception) {
   string str1;
   string* str2 = new string( );
   funcTwo( );
   delete str2;
}
 
void funcTwo( ) throw (exception) {
   ifstream istr;
   istr.open( "filename" );
   throw exception( );
   istr.close( );
}
 

Чтобы избежать этого, можно использовать технику: Catch, Cleanup, и Rethrow (пример называется StackUnwinding\CatchAndRethrow). То есть отлавлить исключение, которое выбрасывает funcTwo(), в функции funcOne() - освободить ресурсы (delete str2;) и передать исключение дальше:
Код
C++ (Qt)
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
 
void funcOne( ) throw (exception);
void funcTwo( ) throw (exception);
 
int main( ) {
   try {
       funcOne( );
   } catch ( const exception& e ) {
       cerr << "Exception caught!" << endl;
       return 1;
   }
 
   return 0;
}
 
void funcOne( ) throw (exception) {
   string str1;
   string* str2 = new string( );
   try {
       funcTwo( );
   } catch ( ... ) {
       delete str2;
       throw; // rethrow the exception
   }
   delete str2;
}
 
void funcTwo( ) throw (exception) {
   ifstream istr;
   istr.open( "filename" );
   throw exception( );
   istr.close( );
}

В Java есть сборщик мусора (как и в C#). А в C++ можно смоделировать сборщик мусора с помощью умных указателей. Писать кода меньше, его легче сопровождать, меньше вероятность допустить ошибку (забыв освободить ресурсы или забыв обработать исключение до освобождения), а так же не надо дублировать следующий код по освобождению ресурсов (delete str2;), как это было в предыдущем примере:
Код
C++ (Qt)
   try {
       funcTwo( );
   } catch ( ... ) {
       delete str2;
       throw; // rethrow the exception
   }
   delete str2;
 

Пример с shared_ptr (или unique_ptr):
Код
C++ (Qt)
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <memory>
 
using namespace std;
 
void funcOne( ) throw (exception);
void funcTwo( ) throw (exception);
 
int main( ) {
   try {
       funcOne( );
   } catch ( const exception& e ) {
       cerr << "Exception caught!" << endl;
       return 1;
   }
 
   return 0;
}
 
void funcOne( ) throw (exception) {
   string str1;
   shared_ptr<string> str2( new string( "hello" ) );
   //unique_ptr<string> str2( new string( "hello" ) );
   funcTwo( );
}
 
void funcTwo( ) throw (exception) {
   ifstream istr;
   istr.open( "filename" );
   throw exception( );
   istr.close( );
}
 
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #46 : Март 27, 2014, 09:19 »

А можно было не выделять память в куче в функциях, а использовать стэковую Улыбающийся
Записан

8Observer8
Гость
« Ответ #47 : Март 27, 2014, 09:27 »

Под строкой: "string* str2 = new string( );" надо подразумевать захват любого ресурса, а под строкой: "delete str2;" - освобождение любого ресурса Улыбающийся
« Последнее редактирование: Март 27, 2014, 09:32 от 8Observer8 » Записан
OKTA
Гость
« Ответ #48 : Март 27, 2014, 09:37 »

А при чем тут совместимость с Си?
Записан
8Observer8
Гость
« Ответ #49 : Март 27, 2014, 09:45 »

Си пробивает бреши в C++, в частности, в работе с исключениями (в отличае от более продуманных C# и Java): см. сборщик мусора в Java (C#) и необходимость использовать технику "Catch, Cleanup, и Rethrow" в C++ (слава Богу есть shared_ptr и unique_ptr).
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #50 : Март 27, 2014, 09:49 »

(слава Богу есть shared_ptr и unique_ptr).
Это частности техники RAII.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Март 27, 2014, 10:04 »

Си пробивает бреши в C++, в частности, в работе с исключениями (в отличае от более продуманных C# и Java): см. сборщик мусора в Java (C#) и необходимость использовать технику "Catch, Cleanup, и Rethrow" в C++ (слава Богу есть shared_ptr и unique_ptr).
Так может Вам переключиться на C# и Java? Они же "более продуманы" Улыбающийся
Вот Вы шпарите по книжкам вещи которые большинство форумчан давно знают. Конечно Вы не делаете ничего плохого, но и смысла пережевывать известное немного. 

От практического программирования все это далековато. То что Вам известны приемы/методы совсем не значит что Вы их с успехом примените. "Вот я побольше выучу, и тогда..." - это ошибка многих. Программирование не было и не будет эксплуатацией памяти (и это хорошо и правильно  Улыбающийся
Записан
OKTA
Гость
« Ответ #52 : Март 27, 2014, 10:10 »

Си пробивает бреши в C++, в частности, в работе с исключениями (в отличае от более продуманных C# и Java): см. сборщик мусора в Java (C#) и необходимость использовать технику "Catch, Cleanup, и Rethrow" в C++ (слава Богу есть shared_ptr и unique_ptr).


В си вообще как таковых исключений нет. А насчет сборщика мусора в С++ вот
Цитировать
Надо отметить, что автоматическая сборка мусора не включена в стандарт C++ по той простой причине, что программа, её использующая, будет всегда работать медленнее, чем если бы сборка мусора не использовалась вообще. Поэтому Бьёрном Страуструпом было предложено перепоручить обязанности сборки мусора внешним библиотекам, не затрагивая самого C++, что может позитивно сказаться на производительности приложений, поскольку программист сам может решить, где и когда ему стоит использовать автоматическое управление памятью. Это и является серьёзным отличием С++ от Java – при использовании Java у программистов просто нет выбора.

А вот и пример сборщика мусора на С++ http://www.rsdn.ru/article/cpp/GCcpp.xml
Записан
8Observer8
Гость
« Ответ #53 : Март 27, 2014, 10:29 »

Цитировать
Надо отметить, что автоматическая сборка мусора не включена в стандарт C++ по той простой причине, что программа, её использующая, будет всегда работать медленнее...
Это было актуально в те далёкие времена. Сейчас и копьюторы стали намного мощнее и сам Java сравнялся с C++ в плане скорости.

Вопрос не в этом, чтобы переходить на другой язык, где есть сборщик мусора, а чтобы отработать полезную привычку писать осознанно и правильно и создавать надёжные программные системы. Использовать техники доступные в C++, чтобы приблизиться к тому идеалу, к которому подошли C# и Java (в плане безопасности программирования).

P.S. Вроде C# обязан языку "Оберон/Компонентный Паскаль" (в плане безопасности программирования). Вот статейка про выход за пределы границ массива: http://www.inr.ac.ru/~info21/blackbox/disciplina/arr_bounds_checks.htm
« Последнее редактирование: Март 27, 2014, 10:30 от 8Observer8 » Записан
Bepec
Гость
« Ответ #54 : Март 27, 2014, 10:36 »

Кхм. Выражу сомнения в возможности Java обрабатывать данные с 4 оптических интерфейсов без 100% загрузки процессора Веселый

PS не стоит думать "да немного медленнее и что с того"? Этих немного медленнее много. Сотни можно сказать Веселый
Записан
OKTA
Гость
« Ответ #55 : Март 27, 2014, 10:48 »

Thank God I've never seen operating systems written on Java or C#  Смеющийся Смеющийся Смеющийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #56 : Март 27, 2014, 11:14 »

Надо отметить, что автоматическая сборка мусора не включена в стандарт C++ по той простой причине, что программа, её использующая, будет всегда работать медленнее...
Дело не в быстрее/медленнее (это "простое" объяснение для широкого круга). Автоматическая сборка мусора противоречит духу/концепциям С/С++.

Вопрос не в этом, чтобы переходить на другой язык, где есть сборщик мусора, а чтобы отработать полезную привычку писать осознанно и правильно и создавать надёжные программные системы. Использовать техники доступные в C++, чтобы приблизиться к тому идеалу, к которому подошли C# и Java (в плане безопасности программирования).
Пока что НИ РАЗУ выученное не было применено удачно, к месту Улыбающийся Ладно, будем надеяться что "и это пройдет"
« Последнее редактирование: Март 27, 2014, 11:16 от Igors » Записан
8Observer8
Гость
« Ответ #57 : Март 27, 2014, 11:37 »

Пока что НИ РАЗУ выученное не было применено удачно, к месту Улыбающийся Ладно, будем надеяться что "и это пройдет"

Как это ни разу? А я же заменил showError() с помощью своих классов исключений Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #58 : Март 27, 2014, 12:02 »

Как это ни разу? А я же заменил showError() с помощью своих классов исключений Улыбающийся
Так это классический анти-паттерн - как НЕ НАДО использовать исключения  Улыбающийся
С книжками/изучением у Вас все отлично, но как только начинаете это тулить куда ни попадя - смех и грех. Без практики теория довольно беспомощна  Улыбающийся
Записан
8Observer8
Гость
« Ответ #59 : Март 27, 2014, 12:16 »

Почему же их не использовать для обработки ошибок? Хотя бы на примере чтения из файла.
Записан
Страниц: 1 2 3 [4] 5 6 7   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.13 секунд. Запросов: 23.