1 Обработка ошибок
1.1 Традиционные подходы
Техники обработки ошибок
- прекратить выполнение
- возвратить значение «ошибка»
- возвратить допустимое значение и оставить программу в ненормальном состоянии
- вызвать функцию обработки ошибок
Вариант 1. Прекратить выполнение программы
char Stack::pop()
{
assert( top != 0 );
return store[--top];
}
Результат:
stack_assert: simple_stack.cpp:61:
char Stack::pop (): Assertion ‘top != 0’ failed.
Abort (core dumped)
Вариант 2. Возвратить ошибку
char Stack::pop() {
return top ? store[--top] : 0;
}
enum tRC {
OK,
BAD_SIZE,
OVERFLOW,
UNDERFLOW
};
tRC Stack::pop(char* c)
{
if (!top) return UNDERFLOW;
*c=store[--top];
return OK;
}
char Stack::pop(tRC* rc) {
if (top) {
*rc=OK;
return store[--top];
}
*rc=UNDERFLOW;
return 0;
}
- Может не быть подходящего значения
- Результат каждого вызова должен проверяться на «ошибку»
Вариант 3. Оставить программу в ненормальном состоянии
char Stack::pop() {
if (top!=0) {
return store[--top];
}
g_Error=UNDERFLOW;
return 0;
}
int main()
{
Stack stack;
char c = stack.pop();
if (g_Error != OK) {
// error occured
}
else {
// OK
}
}
Вариант 4. Вызвать функцию обработки ошибок
void* new (size_t size)
{
for(;;)
{
if (void* p = malloc(size))
return p;
if (!find_memory_somewhere())
return 0;
}
}
1.2 Исключения
Механизм исключений (exceptions):
- Генерация сообщения об ошибке (throw)
- Перехват этих сообщений (catch)
В программе может одновременно существовать только одно исключение.
class Stack {
public:
Stack(int size);
void push(char c);
//...
};
class Overflow {};
class WrongSize {
public:
int wsize;
Wrong_size(int i):
wsize(i) {}
};
void Stack::push(char c) {
if (top<maxSize)
storage[top++] = c;
else
throw Overflow();
}
void f() {
try {
Stack s(10);
s.push('a');
} catch (Overflow ex) {
cerr << "Stack overflow";
}
}
Выбор исключений
Stack::Stack(int size)
{
if ( size > 10000) {
throw WrongSize(size);
} //...
}
char Stack::pop()
{
if (top==0)
throw Underflow();
return storage[--top];
}
void f(unsigned int size)
{
try {
Stack s(size);
s.push('a');
char c = s.pop();
char d = s.pop();
}
catch (WrongSize ws) {
cerr << "Wrong size:" << ws.wsize;
}
catch (Overflow) { /*...*/
}
catch (Underflow) { /*...*/
}
}
Группировка исключений
class Exception {};
class StackError: public Exception {};
class Overflow: public StackError {};
class Underflow: public StackError {};
class WrongSize: public StackError {};
...
try {
Stack s(size);
// ...
}
catch (WrongSize size_exc) {
// process wronsize exception
}
catch (StackError) {
// general processing
}
Перехват исключений

Перехват исключении
try {
//...
}
catch (StackError& se) {
// process Stack Error
}
catch (RuntimeError& ps) {
// process Runtime Error
}
catch (Exception) {
// process Any Internal Exception
}
catch (...) {
// process any other exception
}
Перехват исключений
try {
//...
}
catch (...) {
// Все исключения перехватываются
// здесь
}
catch (Exception* ex) {
// process Any Internal Exception
}
catch (RuntimeError* re) {
// process Runtime Error
}
catch (StackError* se) {
// process Stack Error
}
Повторная генерация
void f()
{
try {
// ...
throw Underflow();
}
catch (RuntimeError& re) {
if ( can_handle_it_completely(re) ) {
// process the exception here
return;
}
else {
do_what_you_can_do(re);
throw;
}
}
}
void g()
{
try {
f();
}
catch (StackError& re) {
// process stack error
}
catch (FileError& re) {
// process file error
}
}
Исключения в конструкторах
Классические подходы:
- Возвратить объект в «неправильном» состоянии
- Присвоить значение глобальной переменной
- Использовать функцию инициализации
- Осуществлять инициализацию при первом вызове функции-члена
Stack::Stack(int i)
{
if ( (i < MIN_SIZE) ||
(i > MAX_SIZE) )
{
throw WrongSize(i);
}
//...
}
Stack* get_stack(int size)
{
try {
Stack* s = new Stack(size);
//...
return s;
}
catch (WrongSize) {
// handle bad stack size
}
}
Объект не создан, пока не завершится выполнение его конструктора
Schedule::Schedule(int i, Date d)
try
: m_stack(i),
m_date(d)
{
// constructor
}
catch (Stack::Bad_Size) {
// handle bad size of the stack member
}
catch (Date::Bad_Date) {
// handle bad date of the date member
}
Исключении и копирование
- Копирующий конструктор подобен другим конструкторам:
- может генерировать исключения
- при этом объект не создается
- Копирующее присваивание перед генерацией исключения должно убедиться, что оба операнда находятся в корректном состоянии
2 Приведение типов
- dynamic_cast
(expr) - static_cast
(expr) - reinterpret_cast
(expr) - const_cast
(expr) - static_cast
dynamic_cast
void f(Employee* pEmp)
{
Programmer *pp = dynamic_cast< Programmer*>(pEmp);
if (pp)
{
pp->team();
}
}
void g(Employee& re)
{
try {
Programmer &rp = dynamic_cast< Programmer&>(re);
} catch (bad_cast) {
//...
}
}
static_cast
Преобразование родственных типов
int *p = static_cast< int* >(malloc(100));
enum tColor {RED, GREEN, BLUE};
tColor c = static_cast< tColor >(2);
double d = 2.56;
int i = static_cast< int >(d);
reinterpret_cast
Преобразование несвязанных типов
IO_device *p = reinterpret_cast< IO_device *>(0XffA01);
void* p = allocate_memory_for_programmer();
Programmer *p = reinterpret_cast< Programmer* >(p);
const_cast
Отмена const
void f(const Worker* pw)
{
Worker *pp = const_cast< Worker*>(pw);
pp->new_name("Vasya");
}
...
const Worker w("Ivan", "Ivanov");
f(*w); //неопределнное поведение
3 Пространства имен
Пространство имен
- Является механизмом отражения логического группирования
- Является областью видимости
namespace My_Lib {
class Stack {/*...*/};
void using_stack(int);
void print_stack(const Stack&);
}
..
void My_Lib::using_stack(int i)
{
Stack st(i);
Chrono::Date date(5, 4, 2004);
Chrono::display(date);
print_stack(st);
}
namespace Chrono {
class Date {/*...*/};
Date next_date(const Date&);
void display(const Date&);
}
//chrono.h
namespace Chrono {
class Date
{
int day, month, year;
public:
Date (int, int, int);
void print() const;
};
void display(const Date&);
}
//chrono.cc
Chrono::Date::Date(int dd, int mm, int yy)
{
//...
}
void Chrono::Date::print() const
{
//...
}
void Chrono::display(const Chrono::Date& rd)
{
rd.print();
}
Использование using
//namesp.cc
int main()
{
// using-объявление
using Chrono::Date;
Date today(2, 4, 2004);
Chrono::display(today);
return 0;
}
//namesp.cc
// using-директива
using namespace Chrono;
int main()
{
Date today(2, 4, 2004);
display(today);
return 0;
}

// user_interface.h
namespace TcpClient {
class TcpBaseClient {
public:
virtual bool connect(const char* pcHostName, int iPort);
virtual int write(void* buf, int size)=0;
virtual int read(void* buf, int size)=0;
};
TcpBaseClient* getTcpClient();
}
// prog_interface.h
namespace TcpClient {
class TcpRealClient: public TcpBaseClient {...};
class TcpClientHandler {...};
map<int, TcpBaseClient> TcpClientPool;
TcpBaseClient* getNextFreeClient();
}
Неименнованные пространства имен
// aa.ccp
namespace {
int a;
int f();
}
void g()
{ a = f(); }
// bb.ccp
namespace {
int a;
int f();
}
// main.cc
namespace {
int a;
int f();
}
int main()
{
a = f();
}
Псевдонимы пространства имен
namespace American_Telephone_and_Telegraph {
class Date {/*...*/}
//...
}
American_Telephone_and_Telegraph::Date d1(5,4,2004);
American_Telephone_and_Telegraph::Date d2(6,4,2004);
namespace ATT = American_Telephone_and_Telegraph;
ATT::Date d3(5,4,2004);
ATT::Date d4(6,4,2004);
namespace Lib = Foundation_library_v2r10;
Lib::Stack s;
Lib::List l;
Объединение пространств имен
//her_lib.h
namespace Her_lib {
class String {...};
String operator+(const String&, const String&);
String operator+(const String&, const char*);
}
//my_lib.h
namespace My_lib {
using namespace Her_lib;
using namespace His_lib;
void my_f(const String&);
}
include "my_lib.h"
void f()
{
My_lib::String s="hello";
//...
}
Объединение и отбор
namespace Her_lib {
class String {...};
String operator+(const String&, const String&);
String operator+(const String&, const char*);
}
namespace My_lib {
using Her_lib::String;
using Her_lib::operator+;
}
namespace My_lib {
using namespace Her_lib;
using namespace His_lib;
using Her_lib::String;
using His_lib::Vector;
void my_f(const String&);
}