22
Лекция 12. Шаблоны, часть вторая. Умные указатели Лекция 12. Шаблоны, часть вторая. Умные указатели Александр Смаль CS центр 8 декабря 2016 Санкт-Петербург http://compscicenter.ru 1/22

Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Embed Size (px)

Citation preview

Page 1: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 12. Шаблоны, часть вторая. Умные указатели

Лекция 12. Шаблоны, часть вторая.Умные указатели

Александр Смаль

CS центр8 декабря 2016

Санкт-Петербург

http://compscicenter.ru 1/22

Page 2: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 3: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 4: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 5: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 6: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 7: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 8: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 9: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 12. Шаблоны, часть вторая. Умные указатели

Компиляция шаблонов∙ Шаблон независимо компилируется для каждого значения

шаблонных параметров.

∙ Компиляция (инстанциирование) шаблона происходит в точкепервого использования — точке инстанциирования шаблона.

∙ Компиляция шаблонов классов — ленивая, компилируютсятолько те методы, которые используются.

∙ В точке инстанциирования шаблон должен быть полностьюопределён.

∙ Шаблоны следует определять в заголовочных файлах.

∙ Все шаблонные функции (свободные функции и методы)являются inline.

∙ В разных единицах трансляции инстанциирование происходитнезависимо.

http://compscicenter.ru 9/22

Page 10: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 12. Шаблоны, часть вторая. Умные указатели

Резюме про шаблоны∙ Большие шаблонные классы следует разделять на два

заголовочных файла: объявление (array.hpp) и определение(array_impl.hpp).

∙ Частичная специализация и шаблонные параметры поумолчанию есть только у шаблонов классов.

∙ Вывод шаблонных параметров есть только у шаблонов функций.

∙ Предпочтительно использовать перегрузку шаблонных функцийвместо их полной специализации.

∙ Полная специализация функций — это обычные функции.

∙ Виртуальные методы, конструктор по умолчанию, конструкторкопирования, оператор присваивания и деструктор не могутбыть шаблонными.

∙ Используйте typedef для длинных шаблонных имён.

http://compscicenter.ru 10/22

Page 11: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 12. Шаблоны, часть вторая. Умные указатели

Умные указатели

1. Идиома RAII (Resource Acquisition Is Initialization): времяжизни ресурса связанно с временем жизни объекта.

∙ Получение ресурса в конструкторе.∙ Освобождение ресурса в деструкторе.

2. Основные области использования RAII:∙ для управления памятью,∙ для открытия файлов или устройств,∙ для мьютексов или критических секций.

3. Умные указатели — объекты, инкапсулирующие владениепамятью. Синтаксически ведут себя так же, как и обычныеуказатели.

http://compscicenter.ru 11/22

Page 12: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 13: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 14: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 15: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 16: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 17: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 18: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 19: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 12. Шаблоны, часть вторая. Умные указатели

Заключение

∙ Умные указатели намного удобнее ручного управления памятью.

∙ Для локальных объектов — scoped_ptr или scoped_array.

∙ Для разделяемых объектов — shared_ptr или shared_array.

∙ Использовать auto_ptr нужно с большой осторожностью, т.к. унего нестандартная семантика присваивания.

∙ В сильносвязанных системах рассмотрите возможностьиспользовать weak_ptr.

∙ Используйте intrusive_ptr для тех объектов, которые самиуправляют своим временем жизни.

∙ Прочитайте документацию по shared_ptr.

http://compscicenter.ru 19/22

Page 20: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 21: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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

Page 22: Программирование на C++, часть 1, осень 2016: Шаблоны, часть 2. Умные указатели

Лекция 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