MyVector.h
#pragma once
template<typename MyVector>
class MyVectorIterator
{
public:
using ValueType = typename MyVector::ValueType;
using PointerType = ValueType*;
using ReferenceType = ValueType&;
public:
MyVectorIterator(PointerType ptr)
:m_Ptr(ptr) {}
MyVectorIterator& operator++()
{
m_Ptr++;
return *this;
}
MyVectorIterator operator++(int)
{
MyVectorIterator iterator = *this;
++(*this);
return iterator;
}
MyVectorIterator& operator--()
{
m_Ptr--;
return *this;
}
MyVectorIterator operator--(int)
{
MyVectorIterator iterator = *this;
--(*this);
return iterator;
}
ReferenceType operator[](int index)
{
return *(m_Ptr + index);
}
PointerType operator->()
{
return m_Ptr;
}
ReferenceType operator*()
{
return *m_Ptr;
}
ReferenceType operator*(int)
{
return *m_Ptr;
}
bool operator==(const MyVectorIterator& other) const
{
return m_Ptr == other.m_Ptr;
}
bool operator!=(const MyVectorIterator& other) const
{
return !(*this == other);
}
private:
PointerType m_Ptr;
};
template<typename T>
class MyVector
{
public:
using ValueType = T;
using Iterator = MyVectorIterator<MyVector<T>>;
public:
MyVector()
{
//allocate 2 elements
ReAlloc(2);
}
void PushBack(const T& value)
{
if (m_Size >= m_Capacity)
{
ReAlloc(m_Capacity * 2);//double it.
}
m_Data[m_Size] = value;
m_Size++;
}
// to avoid data copy
void PushBack(T&& value)
{
if (m_Size >= m_Capacity)
{
ReAlloc(m_Capacity * 2);
}
m_Data[m_Size] = std::move(value);
m_Size++;
}
size_t Size() const { return m_Size; }
template<typename...Args>
T& EmplaceBack(Args&&... args)
{
if (m_Size >= m_Capacity)
{
ReAlloc(m_Capacity * 2);
}
// new() -> advanced tip of the day, for constructing objects in that place.
new(&m_Data[m_Size]) T(std::forward<Args>(args)...);//better than:m_Data[m_Size] = T(std::forward<Args>(args)...);
return m_Data[m_Size++];
}
void PopBack()
{
if (m_Size > 0)
{
m_Size--;
m_Data[m_Size].~T();
}
}
void Clear()
{
for (size_t i = 0; i < m_Size; i++)
{
m_Data[i].~T();
}
m_Size = 0;
}
const T& operator[] (size_t index) const
{
//size check for debug mode.
if (index >= m_Size)
{
__debugbreak();
}
return m_Data[index];
}
T& operator[] (size_t index)
{
//size check for debug mode.
if (index >= m_Size)
{
__debugbreak();
}
return m_Data[index];
}
~MyVector()
{
Clear();
std::cout << "class MyVector destroyed!\n";
//delete[] m_Data;
::operator delete(m_Data, m_Capacity * sizeof(T));//::operator delete won't call any destructors.
}
Iterator begin()
{
return Iterator(m_Data);
}
Iterator end()
{
return Iterator(m_Data + m_Size);
}
private:
void ReAlloc(size_t newCapacity)
{
// allocate a new block of memory
//T* newBlock = new T[newCapacity];//raw pointer->to access memory as low level as we can.
T* newBlock = (T*) ::operator new(newCapacity * sizeof(T));//operator new() won't call any constructor.
//downsize or upsize
if (newCapacity < m_Size)
{
m_Size = newCapacity;
}
// move old elements into the new memory by using a for loop bc need to be
// hitting the copy constructor of all of these elements.
// memcpy() for simple types:int float.
for (size_t i = 0; i < m_Size; i++)
{
//newBlock[i] = std::move(m_Data[i]);
new (&newBlock[i]) T(std::move(m_Data[i]));
}
// clear
for (size_t i = 0; i < m_Size; i++)
{
m_Data[i].~T();
}
// delete the old block.
::operator delete(m_Data, m_Capacity * sizeof(T));// delete[] m_Data;
m_Data = newBlock;
m_Capacity = newCapacity;
}
private:
T* m_Data = nullptr;
size_t m_Size = 0;//the number of element.
size_t m_Capacity = 0;//how much memory we have allocated.
};
main.cpp
#include <iostream>
#include <string>
#include "MyVector.h"
int main(void)
{
MyVector<int> intValues;
intValues.EmplaceBack(1);
intValues.EmplaceBack(2);
intValues.EmplaceBack(3);
intValues.EmplaceBack(4);
intValues.EmplaceBack(5);
MyVector<std::string> strValues;
strValues.EmplaceBack("1");
strValues.EmplaceBack("2");
strValues.EmplaceBack("IamGroot");
strValues.EmplaceBack("4");
strValues.EmplaceBack("5");
std::cout << "---------Not using iterators:---------\n";
for (int i = 0; i < strValues.Size(); i++)
{
std::cout << strValues[i] << std::endl;
}
std::cout << "---------range-based for loop:---------\n";
for (auto& value : strValues)
{
std::cout << value << std::endl;
}
std::cout << "---------iterators:---------\n";
for (MyVector<std::string>::Iterator it = strValues.begin(); it != strValues.end(); it++)
{
std::cout << *it << std::endl;
}
std::cin.get();
}