Upgrade to Pro — share decks privately, control downloads, hide ads and more …

АФТИ ООП 2013-2014. Лекция II/5

АФТИ ООП 2013-2014. Лекция II/5

Oleg Dashevskii

March 17, 2014
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. SINGLETON («ОДИНОЧКА») • Шаблон проектирования. • Гарантирует, что у класса

    есть только один экземпляр, и предоставляет к нему глобальную точку доступа. • Примеры: • Журналирование действий (log). Один-единственный журнал. • Одна-единственная оконная система. • Один-единственный системный таймер. • …
  2. class S {! public:! static S& getInstance() {! static S

    instance; // Гарантированно будет уничтожен.! // Конструируется при первом обращении.! return instance;! }! ! private:! S();! // Закрываем присваивание и копирование! S(S const&); // Реализация не нужна! void operator=(S const&); // Реализация не нужна! };
  3. namespace Original {! class String {! public:! String(); // start

    off empty! ~String(); // free the buffer! String(const String &); // take a full copy! String &operator=(const String &);! ! void append(char); // append one character! private:! char *buf; // allocated buffer! size_t len; // length of buffer! size_t used; // # chars actually used! };! }!
  4. namespace Original {! ! String::String() : buf(0), len(0), used(0) {

    }! ! String::~String() { delete[] buf; }! ! String::String(const String &other)! : buf(new char[other.len]),! len(other.len),! used(other.used)! {! copy(other.buf, other.buf + used, buf);! }! ! String &operator=(const String &other) {! delete[] buf;! buf = new char[len = other.len];! used = other.used;! copy(other.buf, other.buf + used, buf);! return *this;! ! ! ! }! }
  5. namespace Original {! ! void String::reserve(size_t n) {! if (len

    < n) {! size_t newlen = max(len * 1.5, n);! char *newbuf = new char[newlen];! copy(buf, buf + used, newbuf);! ! delete[] buf;! buf = newbuf;! len = newlen;! }! }! ! void String::append(char c) {! reserve(used + 1);! buf[used++] = c;! }! ! }!
  6. namespace Optimized {! struct StringBuf {! StringBuf(); // start off

    empty! ~StringBuf(); // delete the buffer! void reserve(size_t n); // ensure len >= n! ! char* buf; // allocated buffer! size_t len; // length of buffer! size_t used; // # chars actually used! unsigned refs; // reference count! };! ! class String {! public:! String(); // start off empty! ~String(); // decrement reference count! // (delete buffer if refs==0)! String(const String &); // point at same buffer and! // increment reference count! void append(char); // append one character! String &operator=(const String &);! private:! StringBuf *data;! };! } Copy-on-write (COW)
  7. namespace Optimized {! struct StringBuf {! StringBuf(); // start off

    empty! ~StringBuf(); // delete the buffer! void reserve(size_t n); // ensure len >= n! ! char *buf; // allocated buffer! size_t len; // length of buffer! size_t used; // # chars actually used! unsigned refs; // reference count! ! private:! StringBuf(const StringBuf &);! StringBuf &operator=(const StringBuf &);! };! }! Запрещаем нежелательные операции
  8. namespace Optimized {! ! StringBuf::StringBuf() :! buf(0), len(0), used(0), refs(1)

    {}! ! StringBuf::~StringBuf() { delete[] buf; }! ! void StringBuf::reserve(size_t n) {! if (len < n) {! size_t newlen = max(len * 1.5, n);! char *newbuf = new char[newlen];! copy(buf, buf + used, newbuf);! ! delete[] buf;! buf = newbuf;! len = newlen;! }! }! }! Реализация StringBuf
  9. namespace Optimized {! String::String() : data(new StringBuf) {}! ! String::~String()

    {! if (--data->refs < 1) {! delete data;! }! }! ! String::String(const String &other)! : data(other.data) {! ++data->refs;! }! ! String &operator=(const String &other) {! if (--data->refs < 1)! delete data;! ++(data = other.data)->refs;! return *this;! }! }
  10. namespace Optimized {! void String::about_to_modify(size_t n) {! if (data->refs >

    1) {! auto_ptr<StringBuf> newdata(new StringBuf);! newdata->reserve(max(data->len, n));! ! copy(data->buf, data->buf + data->used,! newdata->buf);! newdata->used = data->used;! ! --data->refs;! data = newdata.release();! } else {! data->reserve(n);! }! }! ! void String::append(char c) {! about_to_modify(data->used + 1);! data->buf[data->used++] = c;! }! }
  11. ЗАДАЧА: ЕЩЕ 2 МЕТОДА namespace Optimized {! class String {!

    // ...! ! size_t length() const; // string length! char &operator[](size_t); // element access! };! }!
  12. char &String::operator[](size_t n) {! return *(data->buf + n);! }! Первая

    попытка void f(Optimized::String &s) {! Optimized::String s2(s); // take a copy of the string! s[0] = 'x'; // oops: also modifies s2!! }! FAIL!
  13. char& String::operator[](size_t n) {! about_to_modify(data->len);! return *(data_->buf+n);! } Вторая попытка

    void f(Optimized::String &s) {! char &rc = s[0]; // reference to the 1st char! Optimized::String s2(s); // take a copy of the string! rc = 'x'; // oops: also modifies s2!! } FAIL!
  14. РЕШЕНИЕ ПРОБЛЕМЫ • «Неразделяемый» StringBuf. • Взятие ссылки не только

    копирует буфер, но и помечает его неразделяемым. • Пометка действует до первой операции, изменяющей строку (после нее ссылки все равно можно считать недействительными).
  15. size_t String::Unshareable = numeric_limits<unsigned>::max();! ! StringBuf::StringBuf(const StringBuf &other, size_t n)!

    : buf(0), len(0), used(0), refs(1)! {! reserve(max(other.len, n));! copy(other.buf, other.buf + other.used, buf);! used = other.used;! }! ! void String::about_to_modify(size_t n, bool unshareable /* = false */) {! if (data->refs > 1 && data->refs != Unshareable) {! StringBuf *newdata = new StringBuf(*data, n);! --data->refs;! data = newdata;! } else {! data->reserve(n);! }! ! data->refs = unshareable ? Unshareable : 1;! }! ! char &String::operator[](size_t n) {! about_to_modify(data->len, true);! ! return *(data_->buf+n);! }
  16. String::String(const String &other) {! if (other.data->refs != Unshareable)! ++(data =

    other.data)->refs;! else! data = new StringBuf(*other.data);! }! ! String::~String() {! if (data->refs == Unshareable || --data->refs < 1)! delete data;! }! ! String &operator=(const String &other) {! if (data->refs == Unshareable || --data->refs < 1)! delete data;! ! if (other.data->refs != Unshareable)! ++(data = other.data)->refs;! else! data = new StringBuf(*other.data);! return *this;! }
  17. «БОЛЕВЫЕ ТОЧКИ» • Конструктор копирования. • Оператор присваивания. • Инициализация

    указателей в конструкторе и не только (лечится с помощью smart pointer). • Неявное преобразование типов (лечится с помощью explicit). • Корректная реализация перегрузки операторов.