Өнүккөн долбоор: жалпыланган контейнер
Жыйынтыктоочу долбоор: шаблондуу, жылдырууну колдогон Vec<T> контейнерин итераторлору менен кадам-кадам курабыз
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 жашабайт.