Мазмунга өтүү

Өнүккөн долбоор: жалпыланган контейнер

Сабактын башталышы

Өнүккөн долбоор: жалпыланган контейнер

Жыйынтыктоочу долбоор: шаблондуу, жылдырууну колдогон Vec<T> контейнерин итераторлору менен кадам-кадам курабыз

Негизги идея: Бул курста жолуккан бардык абстракциялар — шаблондор, бештик эрежеси, жылдыруу семантикасы, RAII, кемчиликсиз өткөрүү, өзгөчө кырдаал коопсуздугу жана итераторлор — бир оор маселени чечүү үчүн бар: чийки эстутум блогуна ээлик кылып, анын ичиндеги объекттердин жашоо мөөнөтүн башкарган контейнер, ар кандай элемент түрү үчүн жана бир да ашыкча көчүрмөсүз. Бул жыйынтыктоочу долбоордо биз так ушундай контейнерди долбоорлоп, курабыз: өсүүчү динамикалык массив, аны Vec<T> деп атайбыз — негизи окуу үчүн std::vector. Бөлүктөрдүн кантип биригерин көргөндөн кийин бул жерде эч кандай сыйкыр жок.
Аягында сиз төмөнкүлөрдү жасай аласыз:
  • чийки сактагыч жана placement new аркылуу эстутум бөлүштүрүүнү конструкциялоодон ажыратуу,
  • контейнер туура көчүрүлүп, жылдырылып жана тазаланышы үчүн толук бештик эрежесин ишке ашыруу,
  • коопсуз болгондо элементтерди жылдырган геометриялык өсүүлүү reserve жазуу,
  • push_back жана кемчиликсиз өткөргөн emplace_back кошуу,
  • range-for жана STL алгоритмдери өзүнөн-өзү иштеши үчүн чийки-көрсөткүч итераторлорун берүү.

1. Биз көздөгөн интерфейс

Денесин жазуудан мурун коомдук форманы бекитип алалы. Пайдалуу ырааттуу контейнерге үч сан жана бир нече операция керек. Биз үч талааны сактайбыз: сактагычка көрсөткүч, конструкцияланган элементтердин саны (size) жана сактагыч сыйдыра ала турган слоттордун саны (capacity).

template <typename T>
class Vec {
    T* data_ = nullptr;        // raw block of capacity_ slots
    std::size_t size_ = 0;     // how many are actually constructed
    std::size_t cap_  = 0;     // how many slots exist
public:
    Vec() = default;
    ~Vec();                                  // destroy + free
    Vec(const Vec&);                         // copy
    Vec& operator=(const Vec&);
    Vec(Vec&&) noexcept;                     // move
    Vec& operator=(Vec&&) noexcept;

    void reserve(std::size_t n);             // grow storage
    void push_back(const T& v);
    void push_back(T&& v);
    template <typename... Args>
    T& emplace_back(Args&&... args);         // construct in place

    std::size_t size() const { return size_; }
    std::size_t capacity() const { return cap_; }
    T& operator[](std::size_t i) { return data_[i]; }

    T* begin() { return data_; }             // iterators = raw pointers
    T* end()   { return data_ + size_; }
};

Эң маанилүү ой — size менен capacity айырмасы. Capacity — биз канча эстутум кармап турабыз; size — ошол эстутумдун башын канча тирүү объект ээлеп турат. Алардын ортосундагы боштук — чийки, инициализацияланбаган байттар: ал жерде азырынча бир да T жашабайт.

Бул сабакты YourAIZone платформасында улантыңыз

Толук сабакта — толук түшүндүрмө, чыгарылган мисалдар, көп кездешкен каталар, заматта текшерилүүчү тесттер жана ЖИ-репетитор. Конок катары дароо баштаңыз же прогрессти сактоо үчүн аккаунт түзүңүз.

Толук сабакта

  • Толук түшүндүрмө
  • Чыгарылган мисалдар
  • Көп кездешкен каталар жана алардан кантип качуу керек
  • Тест суроолору: 15
  • Тема боюнча суроолорго жооп берген ЖИ-репетитор
  • Окуучу, ата-эне жана мугалим үчүн прогрессти көзөмөлдөө