c++ 2: boost::bind & boost::function
Post on 07-Jul-2015
190 Views
Preview:
TRANSCRIPT
Лекция 6. Исключения
Valery Lesin. C++ In-Depth, 2014 1
Способы обработки ошибок
• Ошибка повод для std::terminate
• Вернуть признак ошибки и выставить
глобальный код ошибки
• Вернуть код ошибки
• Бросить исключение:
– его невозможно проигнорировать;
– распространяется автоматически;
– выносит обработку из основного потока
выполнения
– незаменимо в конструкторах или операторах.
Valery Lesin. C++ In-Depth, 2014 2
try...catch
Valery Lesin. C++ In-Depth, 2014 3
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
try
{
// throws explicit or implicit
throw exception_type(/*...*/);
//...
}
catch(std::exception const& err)
{/*...*/}
catch(...)
{
/*...*/
throw;
}
//...
Type::Type(/*...*/)
try
: field1_(/*...*/)
, field2_(/*...*/)
{
/*...*/
}
catch(std::exception const&)
{
/*some logging*/
throw;
}
Типы исключений
• Исключение может быть любым типом (хоть int или const char*)
• Разумно делать класс исключения, наследуя его от std::exception (и реализовать what)
• Есть стандартные исключения, например, std::runtime_error, logic_error (<stdexcept>)
• Перерехват по
– точному соответствию типа;
– ссылке на базовый класс;
– по приводимому указателю.
Valery Lesin. C++ In-Depth, 2014 4
Использование RAII
• Есть ли проблемы в этом коде?
Valery Lesin. C++ In-Depth, 2014 5
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
double sqrt(double value)
{
if (value < 0) throw runtime_error("nagative");
/*...*/
}
double* make_roots(double* values, size_t size)
{
double* roots = new double[size];
transform(values, values + size, roots, sqrt);
return roots;
}
Использование RAII (2)
• Есть ли проблемы в этом коде?
Valery Lesin. C++ In-Depth, 2014 6
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
double* make_roots(double* values, size_t size)
{
double* roots = new double[size];
try
{
transform(values, values + size, roots, sqrt);
}
catch(std::exception const& err)
{
delete [] roots;
cerr << err.what() << endl;
throw;
}
return roots;
}
double* make_roots(double* values, size_t size)
{
unique_ptr<double> roots(new double[size]);
transform(values, values + size, roots.get(), sqrt);
return roots.release();
}
Передача параметров
• Исправляет ли вызов в (10) ошибочный вызов в (3)?
Valery Lesin. C++ In-Depth, 2014 7
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
void foo(T* a, U* b);
/*...*/
void foo(new T(/*...*/), new U(/*...*/));
typedef shared_ptr<T> T_ptr;
typedef shared_ptr<U> U_ptr;
void foo(T_ptr a, U_ptr b);
/*...*/
void foo(T_ptr(new T(/*...*/)), U_ptr(new U(/*...*/)));
Передача параметров(2)
• Если для соответствующего RAII класса нет фабрики, используйте способ (1).
Valery Lesin. C++ In-Depth, 2014 8
1.
2.
3.
4.
5.
6.
7.
8.
9.
void foo(T_ptr a, U_ptr b);
//(1)
T_ptr a(new T(/*...*/));
U_ptr b(new U(/*...*/));
foo(a, b);
// (2)
foo(make_shared<T>(/*...*/), make_shared<U>(/*...*/));
Класс stack
• Попробуем разработать безопасную
реализацию класса stack
Valery Lesin. C++ In-Depth, 2014 9
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
template<class T> struct stack
{
stack(size_t def_size = 10);
~stack();
T pop();
void push(T const&);
/*...*/
private:
size_t size_; // buffer size
size_t used_; // number of objects
T* buf_ ; // main buffer
};
Класс stack, конструктор
• Такой код нейтрален – любое исключение
передается дальше.
• Не вызывает утечек памяти.
• Независимо от наличия исключений стек
остается согласованным (либо
несозданным).
Valery Lesin. C++ In-Depth, 2014 10
1.
2.
3.
4.
5.
6.
template<class T>
stack<T>::stack(size_t def_size)
: size_(def_size)
, used_(0)
, buf_ (new T[def_size])
{}
Гарантии безопасности исключений
• Базовая гарантия: даже при наличии генерируемых объектом класса T (или иных) исключений утечки в классе stack отсутствуют (согласованность).
• Строгая гарантия: если операция прекращается из-за генерации исключения, состояние программы остается неизменным (rollback).
• Гарантия отсутствия исключений: функция не генерирует исключений ни при каких обстоятельствах.
Valery Lesin. C++ In-Depth, 2014 11
Гарантия отсутствия исключений
• Деструкторы:
Что будет, если 13-й объект при создании
бросит исключение, а затем 12-й при
удалении?
• Функция swap
Valery Lesin. C++ In-Depth, 2014 12
1. Type array [42];
Копирование стека• Воспользуемся вспомогательной функцией:
Valery Lesin. C++ In-Depth, 2014 13
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
18.
19.
template<class T>
T* new_copy(const T* src, size_t src_size, size_t
dst_size)
{
// could be made via unique_ptr
T* dst = new T[dst_size];
try
{
copy(src, src + src_size, dst);
}
catch(...)
{
delete[] dst;
throw;
}
return dst;
}
Копирование стека (2)
Valery Lesin. C++ In-Depth, 2014 14
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
18.
19.
20.
21.
22.
template<class T>
stack<T>::stack(stack const& o)
: buf_ (new_copy(o.buf_, o.src_size, o.dst_size))
, size_(o.size_)
, used_(o.used_)
{
}
template<class T>
stack<T>& stack<T>::operator=(stack<T> const& o)
{
if (this != other)
{
T* cp = new_copy(o.buf_, o.src_size, o.dst_size);
delete[] buf_; // no more exceptions
buf_ = cp;
size_ = o.size_;
used_ = o.used_;
}
return *this;
}
push / pop
Valery Lesin. C++ In-Depth, 2014 15
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
template<class T>
void stack<T>::push(T const& t)
{
if (used_ == size_)
{
size_t sz = 2 * size_ + 1;
T* cp = new_copy(buf_, size_, sz);
delete [] buf_; // now ok
buf_ = cp;
size_ = sz;
}
buf_[used_] = t;
++used_;
}
template<class T>
T stack<T>::pop()
{
if (empty()) throw /*...*/;
T res = buf[used_ - 1];
--used_;
return res; // what to do?
}
pop / top
Valery Lesin. C++ In-Depth, 2014 16
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
template<class T>
T& stack<T>::top()
{
if (empty()) throw /*...*/;
return buf[used_ - 1];
}
template<class T>
void stack<T>::pop()
{
if (empty()) throw /*...*/;
--used_;
}
• Разделим pop на pop и top:
Гарантии и требования stack
• Требования:
– наличие конструктора по умолчанию;
– наличие копирующего конструктора;
– деструктор без исключений;
– безопасный оператор присваивания.
• Гарантии:
– строгая гарантия при удовлетворении
требований.
Valery Lesin. C++ In-Depth, 2014 17
Уменьшение требований stack
• Для начала рассмотрим функции:
Valery Lesin. C++ In-Depth, 2014 18
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
template<class T1, class T2>
void construct(T1* p, T2 const& value)
{ new (p) T1(value); }
template<class T>
void destroy(T* p)
{ p->~T();}
template<class fwd_it>
void destroy(fwd_it beg, fwd_it end)
{
while (beg != end)
{
destroy(&*beg);
++beg;
}
}
stack_impl
Valery Lesin. C++ In-Depth, 2014 19
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
stack_impl::stack_impl(size_t size)
: buf (static_cast<T*>(size == 0 ?
0 : new char[size * sizeof(T)])
, size(size)
, used(0)
{}
stack_impl::~stack_impl()
{
destroy(buf, buf + used);
delete static_cast<void*>(buf);
}
• Сделаем вспомогательный класс:
Новый вариант stack
Valery Lesin. C++ In-Depth, 2014 20
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
struct stack
{
/**/
stack_impl impl_;
}
stack::stack(size_t def_size)
: impl_(def_size)
{}
stack::stack(stack const& o)
: impl_(o.impl_.used)
{
while (used < o.impl_.used)
{
construct(impl_.buf + impl_.used,
o.impl_.buf + impl_.used);
++impl_.used;
}
}
stack& stack::operator=(stack o)
{
swap(*this, o);
return *this;
}
To be continued…
Valery Lesin. C++ In-Depth, 2014 21
top related