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

Лекция 3. «Чёрные ящики» (ч. 1)

Лекция 3. «Чёрные ящики» (ч. 1)

ООП АФТИ 2015-2016. Второй семестр

Oleg Dashevskii

February 22, 2016
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. struct Point { double x, y, z; Point() = default;

    Point(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {} }; Point a(10, 20, 30); Point b(a); Point c(Point(1, 2, 3)); Point d; Конструктор, определенный 
 пользователем Конструктор копирования
 (неявный) Конструктор по умолчанию Конструктор перемещения
 (неявный)
  2. КОНСТРУКТОР КОПИРОВАНИЯ Point zeroPoint() { return Point(0, 0, 0); }

    1. Объект является возвращаемым значением
  3. ВАРИАНТЫ X(const X& copy_from_me); X(X& copy_from_me); X(volatile X& copy_from_me); X(const

    volatile X& copy_from_me); X(X& copy_from_me, int = 0); X(const X& copy_from_me, double = 1.0, int = 42);
  4. struct Point { double x, y, z; Point(double _x, double

    _y, double _z) : x(_x), y(_y), z(_z) {} // Не надо такое писать! Point(const Point &other) : x(other.x), y(other.y), z(other.z) {} }; Такой конструктор можно не писать, 
 он будет сгенерирован автоматически 
 (копирование всех полей)
  5. struct Buffer { char *buf; size_t size; Buffer(size_t sz) :

    buf(new char[sz]), size(sz) {} ~Buffer() { delete buf; } }; Как здесь будет работать КК по умолчанию?
  6. Buffer::Buffer(const Buffer &other) : size(other.size) { buf = new char[size];

    if (buf) memcpy(buf, other.buf, size); } Иначе: будет очень-очень плохо!
  7. Buffer fillBuffer() { Buffer b(1024); memset(b.buf, 0, b.size); return b;

    } Buffer mybuf = fillBuffer(); Насколько хорошо и быстро будет
 это работать?
  8. 1. Конструктор A() внутри fillBuffer(). 2. Конструктор копирования во временное

    значение при return. 3. Конструктор копирования в mybuf. В наихудшем случае:
  9. КОНСТРУКТОР ПЕРЕМЕЩЕНИЯ struct Buffer { char *buf; size_t size; Buffer(size_t

    sz); Buffer(const Buffer &other); Buffer(Buffer &&other) { buf = other.buf; size = other.size; other.buf = nullptr; other.size = 0; } ~Buffer(); };
  10. • Foo & – обычная lvalue-ссылка. Можно изменять объект, на

    который она ссылается. • Foo const & – константная lvalue-ссылка. Объект изменять нельзя. • Foo && – rvalue-ссылка. Ссылка на временный объект, который можно изменять, поскольку он всё равно больше использоваться не будет. «Деструктивное чтение».
  11. // Классический swap template<class T> void swap(T& a, T& b)

    { T tmp {a}; // две копии a a = b; // две копии b b = tmp; // две копии tmp (старое a) }
  12. // Почти идеальный swap template<class T> void swap(T& a, T&

    b) { T tmp {static_cast<T&&>(a)}; // конструктор может затереть a a = static_cast<T&&>(b); // присваивание может затереть b b = static_cast<T&&>(tmp); // присваивание может затереть tmp } // То же самое, с использованием std::move template<class T> void swap(T& a, T& b) { T tmp {std::move(a)}; // перемещаем из a a = std::move(b); // перемещаем из b b = std::move(tmp); // перемещаем из tmp }
  13. ПЕРЕГРУЗКА ОПЕРАТОРА ПРИСВАИВАНИЯ • Существует реализация по умолчанию: копирование всех

    полей. • Если в классе присутствуют указатели, реализация по умолчанию приносит проблемы.
  14. struct Buffer { char *buf; size_t size; Buffer(size_t sz) :

    buf(new char[sz]), size(sz) {} ~Buffer() { delete buf; } }; Buffer b1(100), b2(200); b1 = b2; // ОЙ
  15. Buffer &Buffer::operator=(const Buffer &other) { delete buf; buf = new

    char[size = other.size]; if (buf) memcpy(buf, other.buf, size); return *this; } Buffer buf(100), buf2(200); buf = buf; // ОЙ
  16. Buffer &Buffer::operator=(const Buffer &other) { if (this != &other) {

    delete buf; buf = new char[size = other.size]; if (buf) memcpy(buf, other.buf, size); } return *this; } Защита от самоприсваивания
  17. Buffer &Buffer::operator=(Buffer &&other) { buf = other.buf; buf.size = other.size;

    other.buf = nullptr; other.size = 0; return *this; } Присваивание с перемещением
  18. ОПЕРАЦИИ ПО УМОЛЧАНИЮ • X() • X(const X &) •

    X& operator=(const X &) • X(X &&) • X& operator=(X &&) • ~X()
  19. struct S { string a; int b; }; S f(S

    arg) { S s0 {}; // конструктор по умолчанию: {"",0} S s1 {s0}; // конструктор копирования s1 = arg; // копирующее присваивание return s1; // конструктор перемещения }
  20. • Если явно определён любой конструктор, конструктор по умолчанию X()

    не генерируется. • Если явно объявлена любая операция копирования, перемещения или деструктор, то операции копирования, перемещения и деструктор не генерируются. Но: