Last active
June 13, 2025 18:31
-
-
Save advnpzn/f265a4f89270e2da29d1d5ef556b2533 to your computer and use it in GitHub Desktop.
A basic non-thread safe implementation of vector (dynamic array) data structure in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <cstddef> | |
#include <initializer_list> | |
#include <iostream> | |
#include <memory> | |
#include <stdexcept> | |
template <typename T> class Vector { | |
private: | |
T *data_ = nullptr; | |
size_t size_ = 0; | |
size_t capacity_ = 0; | |
public: | |
Vector() = default; | |
explicit Vector(const size_t &count) | |
: data_(new T[count]), size_(count), capacity_(count) {} | |
Vector(size_t count, const T &value) : Vector(count) { | |
std::fill_n(data_, size_, value); | |
} | |
Vector(std::initializer_list<T> init) : Vector(init.size()) { | |
std::copy(init.begin(), init.end(), data_); | |
} | |
~Vector() { | |
std::destroy(data_, data_ + size_); | |
delete[] data_; | |
} | |
Vector(const Vector &other) : Vector(other.size_) { | |
std::copy(other.data_, other.data_ + other.size_, data_); | |
} | |
Vector(Vector &&other) noexcept | |
: data_(other.data_), size_(other.size_), capacity_(other.capacity_) { | |
other.data_ = nullptr; | |
other.size_ = 0; | |
other.capacity_ = 0; | |
} | |
Vector &operator=(const Vector &other) { | |
if (this != &other) { | |
Vector temp(other); | |
swap(other); | |
} | |
return *this; | |
} | |
Vector &operator=(Vector &&other) noexcept { | |
if (this != &other) { | |
delete[] data_; | |
data_ = other.data_; | |
size_ = other.size_; | |
capacity_ = other.capacity_; | |
other.data_ = nullptr; | |
other.size_ = 0; | |
other.capacity_ = 0; | |
} | |
return *this; | |
} | |
T &operator[](const size_t &pos) { | |
if (pos >= size_) { | |
throw std::out_of_range("Index out of range"); | |
} | |
return data_[pos]; | |
} | |
T &at(const size_t &pos) { | |
if (pos >= size_) { | |
throw std::out_of_range("Index out of range"); | |
} | |
return data_[pos]; | |
} | |
size_t size() const noexcept { return size_; } | |
size_t capacity() const noexcept { return capacity_; } | |
bool empty() const noexcept { return size_ == 0; } | |
T &front() { | |
if (empty()) { | |
throw std::out_of_range("Vector is empty"); | |
} | |
return data_[0]; | |
} | |
T &back() { | |
if (empty()) { | |
throw std::out_of_range("Vector is empty"); | |
} | |
return data_[size_ - 1]; | |
} | |
T *data() noexcept { return data_; } | |
void clear() noexcept { | |
std::destroy(data_, data_ + size_); | |
size_ = 0; | |
} | |
void push_back(const T &value) { | |
if (size_ == capacity_) { | |
reserve(capacity_ ? capacity_ * 2 : 1); | |
} | |
data_[size_] = value; | |
++size_; | |
} | |
void push_back(T &&value) { | |
if (size_ == capacity_) { | |
reserve(capacity_ ? capacity_ * 2 : 1); | |
} | |
data_[size_] = std::move(value); | |
++size_; | |
} | |
void shrink_to_fit() { | |
if (size_ < capacity_) { | |
Vector temp(*this); | |
swap(temp); | |
} | |
} | |
template <typename... Args> void emplace_back(Args &&...args) { | |
if (size_ == capacity_) { | |
reserve(capacity_ ? capacity_ * 2 : 1); | |
} | |
new (&data_[size_]) T(std::forward<Args>(args)...); | |
++size_; | |
} | |
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { | |
if (empty()) { | |
throw std::out_of_range("Vector is empty"); | |
} | |
std::destroy_at(std::addressof(data_[size_ - 1])); | |
--size_; | |
} | |
void resize(const size_t &new_size) { | |
if (new_size < size_) { | |
std::destroy(data_ + new_size, data_ + size_); | |
size_ = new_size; | |
} else if (new_size > size_) { | |
reserve(new_size); | |
std::uninitialized_value_construct(data_ + size_, data_ + new_size); | |
size_ = new_size; | |
} | |
} | |
void resize(const size_t &new_size, const T &value) { | |
if (new_size < size_) { | |
std::destroy(data_ + new_size, data_ + size_); | |
size_ = new_size; | |
} else if (new_size > size_) { | |
reserve(new_size); | |
std::uninitialized_fill(data_ + size_, data_ + new_size, value); | |
size_ = new_size; | |
} | |
} | |
void swap(Vector &other) noexcept { | |
std::swap(data_, other.data_); | |
std::swap(size_, other.size_); | |
std::swap(capacity_, other.capacity_); | |
} | |
void reserve(const size_t &new_capacity) { | |
if (new_capacity > capacity_) { | |
T *new_data = new T[new_capacity]; | |
std::uninitialized_move(data_, data_ + size_, new_data); | |
std::destroy(data_, data_ + size_); | |
delete[] data_; | |
data_ = new_data; | |
capacity_ = new_capacity; | |
} | |
} | |
T *begin() noexcept { return data_; } | |
T *end() noexcept { return data_ + size_; } | |
}; | |
int main() { | |
Vector<int> vec = {1, 2, 3, 4, 5}; | |
vec.push_back(6); | |
vec.emplace_back(7); | |
vec.resize(10, 0); | |
for (const auto &item : vec) { | |
std::cout << item << " "; | |
} | |
std::cout << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment