Программирование на c++, часть 1, осень 2016: Шаблоны, часть...
TRANSCRIPT
Лекция 12. Шаблоны, часть вторая. Умные указатели
Лекция 12. Шаблоны, часть вторая.Умные указатели
Александр Смаль
CS центр8 декабря 2016
Санкт-Петербург
http://compscicenter.ru 1/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Полная специализация шаблонов: классыtemplate <class T>struct Array {
...T * data_;
};template <>struct Array <bool > {
static unsigned const BITS = 8 * sizeof(unsigned );explicit Array(size_t size)
: size_(size), data_(new unsigned[size_ / BITS + 1])
{}bool operator []( size_t i) const {
return data_[i / BITS] & (1 << (i % BITS ));}
private:size_t size_;unsigned * data_;
};
http://compscicenter.ru 2/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Полная специализация шаблонов: функцииtemplate <class T>void swap(T & a, T & b){
T tmp(a);a = b;b = tmp;
}
template <>void swap <Database >( Database & a, Database & b){
a.swap(b);}
template <class T>void swap(Array <T> & a, Array <T> & b){
a.swap(b);}
http://compscicenter.ru 3/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Специализация шаблонов и перегрузка
template <class T>void foo(T a, T b) { cout << "same types" << endl; }
template <class T, class V>void foo(T a, V b) { cout << "different types" << endl; }
template <>void foo <int , int >(int a, int b) {
cout << "both parameters are int" << endl;}
int main() {foo(3, 4);return 0;
}
http://compscicenter.ru 4/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Частичная специализация шаблоновtemplate <class T>struct Array {
T & operator []( size_t i) { return data_[i]; }...
};
template <class T>struct Array <T *> {
explicit Array(size_t size): size_(size), data_(new T *[size_ ])
{}
T & operator []( size_t i) { return *data_[i]; }
private:size_t size_;T ** data_;
};
http://compscicenter.ru 5/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Нетиповые шаблонные параметрыПараметрами шаблона могут быть типы, целочисленные значения,указатели/ссылки на значения с внешней линковкой и шаблоны.
template <class T, size_t N, size_t M>struct Matrix {
...T & operator ()( size_t i, size_t j){ return data_[M * j + i]; }
private:T data_[N * M];
};
template <class T, size_t N, size_t M, size_t K>Matrix <T, N, K> operator *(Matrix <T, N, M> const& a,
Matrix <T, M, K> const& b);
// log - это глобальная переменнаяtemplate <ofstream & log >struct FileLogger { ... };
http://compscicenter.ru 6/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Шаблонные параметры — шаблоны// int –> stringstring toString( int i );
// работает только с Array<>Array <string > toStrings( Array <int > const& ar ) {
Array <string > result(ar.size ());for (size_t i = 0; i != ar.size (); ++i)
result.get(i) = toString(ar.get(i));return result;
}
// от контейнера требуются: конструктор от size, методы size() и get()template <template <class > class Container >Container <string > toStrings(Container <int > const& c) {
Container <string > result(c.size ());for (size_t i = 0; i != c.size (); ++i)
result.get(i) = toString(c.get(i));return result;
}
http://compscicenter.ru 7/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Использование зависимых имёнtemplate <class T>struct Array {
typedef T value_type;...
private:size_t size_;T * data_;
};
template <class Container >bool contains(Container const& c,
typename Container :: value_type const& v);
int main(){
Array <int > a(10);contains(a, 5);return 0;
}
http://compscicenter.ru 8/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Компиляция шаблонов∙ Шаблон независимо компилируется для каждого значения
шаблонных параметров.
∙ Компиляция (инстанциирование) шаблона происходит в точкепервого использования — точке инстанциирования шаблона.
∙ Компиляция шаблонов классов — ленивая, компилируютсятолько те методы, которые используются.
∙ В точке инстанциирования шаблон должен быть полностьюопределён.
∙ Шаблоны следует определять в заголовочных файлах.
∙ Все шаблонные функции (свободные функции и методы)являются inline.
∙ В разных единицах трансляции инстанциирование происходитнезависимо.
http://compscicenter.ru 9/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Резюме про шаблоны∙ Большие шаблонные классы следует разделять на два
заголовочных файла: объявление (array.hpp) и определение(array_impl.hpp).
∙ Частичная специализация и шаблонные параметры поумолчанию есть только у шаблонов классов.
∙ Вывод шаблонных параметров есть только у шаблонов функций.
∙ Предпочтительно использовать перегрузку шаблонных функцийвместо их полной специализации.
∙ Полная специализация функций — это обычные функции.
∙ Виртуальные методы, конструктор по умолчанию, конструкторкопирования, оператор присваивания и деструктор не могутбыть шаблонными.
∙ Используйте typedef для длинных шаблонных имён.
http://compscicenter.ru 10/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Умные указатели
1. Идиома RAII (Resource Acquisition Is Initialization): времяжизни ресурса связанно с временем жизни объекта.
∙ Получение ресурса в конструкторе.∙ Освобождение ресурса в деструкторе.
2. Основные области использования RAII:∙ для управления памятью,∙ для открытия файлов или устройств,∙ для мьютексов или критических секций.
3. Умные указатели — объекты, инкапсулирующие владениепамятью. Синтаксически ведут себя так же, как и обычныеуказатели.
http://compscicenter.ru 11/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Основные стратегии1. scoped_ptr — время жизни объекта ограничено временем
жизни умного указателя.2. shared_ptr — разделяемый объект, реализация с
подсчётом ссылок.3. intrusive_ptr — разделяемый объект, реализация самим
внутри объекта.4. linked_ptr — разделяемый объект, реализация списком
указателей.5. auto_ptr, unique_ptr — эксклюзивное владение объектом
с передачей владения при присваивании.6. weak_ptr — разделяемый объект, реализация с подсчётом
ссылок, слабая ссылка (используется вместе сshared_ptr).
http://compscicenter.ru 12/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
scoped_ptr∙ Простой умный указатель: для хранения на стеке или в классе.
∙ Единственные владелец.
∙ Нельзя копировать и присваивать.
∙ Нельзя вернуть владение объектом.
template <class T> struct scoped_ptr {explicit scoped_ptr(T * p = 0) : p_(p) {}~scoped_ptr (){ delete p_; }...void reset(T * p = 0) { delete p_; p_ = p;}T * get() const { return p_; }
private:scoped_ptr(scoped_ptr const &);scoped_ptr operator =( scoped_ptr const &);
T * p_;};
http://compscicenter.ru 13/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
shared_ptr∙ Для разделяемых объектов.
∙ Ведётся подсчёт ссылок.
∙ Нельзя вернуть владение объектом.
template <class T> struct shared_ptr {explicit shared_ptr(T * p = 0) : p_(p), c_(0) {
if (p_) c_ = new size_t (1);}shared_ptr(shared_ptr const& ptr) : p_(ptr.p_), c_(ptr.c_) {
if(c_) ++*c_;}~shared_ptr () { if (c_ && (--*c_ == 0)) delete p_, delete c_; }...
private:T * p_;size_t * c_;
};
http://compscicenter.ru 14/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
intrusive_ptr∙ Для разделяемых объектов.
∙ Объект самостоятельно управляет своим временем жизни.
∙ Нельзя вернуть владение объектом.
template <class T> struct intrusive_ptr {explicit intrusive_ptr(T * p = 0) : p_(p) {
if (p_) intrusive_addref(p_);}intrusive_ptr(intrusive_ptr const& ptr) : p_(ptr.p) {
if (p_) intrusive_addref(p_);}~intrusive_ptr () {
if (p_) intrusive_release(p_);}...
private:T * p_;
};http://compscicenter.ru 15/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
linked_ptr
∙ Для разделяемых объектов.
∙ Указатели на один объект объединяются в список, исключаетнеобходимость дополнительного выделения памяти.
∙ Нельзя вернуть владение объектом.
template <class T>struct linked_ptr {
...// Home assignment №3...
private:linked_ptr * next;linked_ptr * prev;T * p_;
};
http://compscicenter.ru 16/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
auto_ptr, unique_ptr∙ Для передачи и возврата указателей из функции.
∙ Владение эксклюзивно и передаётся при присваивании.
template <class T> struct auto_ptr {explicit auto_ptr(T * p = 0) : p_(p) {}auto_ptr(auto_ptr & ptr) : p_(ptr.p_) { ptr.p_ = 0; }~auto_ptr (){ delete p_; }auto_ptr & operator =( auto_ptr & ptr) {
it (this == &ptr) return *this;delete p_;p_ = ptr.p_;ptr.p_ = 0;return *this;
}T * release () { T * t = p_; p_ = 0; return t; }
private:T * p_;
};
http://compscicenter.ru 17/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
weak_ptr∙ Для использования вместе с shared_ptr.
∙ Слабая ссылка для исключения циклических зависимостей.
∙ Не владеет объектом.
template <class T> struct counter {size_t links;size_t weak_links;T * data_;
};
template <class T> struct weak_ptr {explicit weak_ptr(shared_ptr <T> ptr);shared_ptr <T> lock ();...
private:counter <T> * c_;
};
http://compscicenter.ru 18/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Заключение
∙ Умные указатели намного удобнее ручного управления памятью.
∙ Для локальных объектов — scoped_ptr или scoped_array.
∙ Для разделяемых объектов — shared_ptr или shared_array.
∙ Использовать auto_ptr нужно с большой осторожностью, т.к. унего нестандартная семантика присваивания.
∙ В сильносвязанных системах рассмотрите возможностьиспользовать weak_ptr.
∙ Используйте intrusive_ptr для тех объектов, которые самиуправляют своим временем жизни.
∙ Прочитайте документацию по shared_ptr.
http://compscicenter.ru 19/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Safe bool: проблемаstruct Testable {
operator bool() const { return false; }
};
struct AnotherTestable {
operator bool() const { return true; }
};
int main (void)
{
Testable a;
AnotherTestable b;
if (a == b) { /* blah blah blah*/ }
if (a < 0) { /* blah blah blah*/ }
return 0;
}
http://compscicenter.ru 20/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Safe bool idiomstruct Testable {
explicit Testable(bool b=true): ok_(b) {}
operator bool_type () const {
return ok_ ?
& Testable :: this_type_does_not_support_comparisons : 0;
}
private:
typedef void (Testable ::* bool_type )() const;
void this_type_does_not_support_comparisons () const {}
bool ok_;
};
struct AnotherTestable {...};.
http://compscicenter.ru 21/22
Лекция 12. Шаблоны, часть вторая. Умные указатели
Safe bool idiom (cont.)
...
template <typename T>
bool operator <(const Testable& lhs , const T&) {
lhs.this_type_does_not_support_comparisons ();
return false;
}
...
int main() {
Testable t1;
AnotherTestable t2;
if (t1) {} // Works as expected
if (t2 == t1) {} // Fails to compile
if (t1 < 0) {} // Fails to compile
return 0;
}
http://compscicenter.ru 22/22