For learning purposes, I decided to implement my own vector data structure. I called it list because that seems to generally be the more proper name for it but that's unimportant.
I am halfway through implementing this class (inserting and getting are complete) and I decide to write some benchmarks with surprising results.
My compiler is whatever Visual Studio 2019 uses. I have tried debug and release, in x64 and x86.
For some reason, my implementation is faster than vector and I cannot think of a reason why. I fear that either my implementation or testing method are flawed.
Here are my results (x64, debug):
List: 13269ms
Vector: 78515ms
Release has a much less drastic, but still apparent, difference.
List: 65ms
Vector: 247ms
Here is my code
dataset.hpp:
#ifndef DATASET_H
#define DATASET_H
#include <memory>
#include <stdexcept>
#include <algorithm>
#include <functional>
#include <chrono>
namespace Dataset {
    template <class T>
    class List {
    public:
        List();
        List(unsigned int);
        void push(T);
        T& get(int);
        void reserve(int);
        void shrink();
        int count();
        int capacity();
        ~List();
    private:
        void checkCapacity(int);
        void setCapacity(int);
        char* buffer;
        int mCount, mCapacity;
    };
    template <class T>
    List<T>::List() {
        mCount = 0;
        mCapacity = 0;
        buffer = 0;
        setCapacity(64);
    }
    template <class T>
    List<T>::List(unsigned int initcap) {
        mCount = 0;
        buffer = 0;
        setCapacity(initcap);
    }
    template <class T>
    void List<T>::push(T item) {
        checkCapacity(1);
        new(buffer + (sizeof(T) * mCount++)) T(item);
    }
    template <class T>
    T& List<T>::get(int index) {
        return *((T*)(buffer + (sizeof(T) * index)));
    }
    template <class T>
    void List<T>::reserve(int desired) {
        if (desired > mCapacity) {
            setCapacity(desired);
        }
    }
    template <class T>
    void List<T>::shrink() {
        if (mCapacity > mCount) {
            setCapacity(mCount);
        }
    }
    template <class T>
    int List<T>::count() {
        return mCount;
    }
    template <class T>
    int List<T>::capacity() {
        return mCapacity;
    }
    template <class T>
    void List<T>::checkCapacity(int cap) {
        // Can <cap> more items fit in the list? If not, expand!
        if (mCount + cap > mCapacity) {
            setCapacity((int)((float)mCapacity * 1.5));
        }
    }
    template <class T>
    void List<T>::setCapacity(int cap) {
        mCapacity = cap;
        // Does buffer exist yet?
        if (!buffer) {
            // Allocate a new buffer
            buffer = new char[sizeof(T) * cap];
        }
        else {
            // Reallocate the old buffer
            char* newBuffer = new char[sizeof(T) * cap];
            if (newBuffer) {
                std::copy(buffer, buffer + (sizeof(T) * mCount), newBuffer);
                delete[] buffer;
                buffer = newBuffer;
            }
            else {
                throw std::runtime_error("Allocation failed");
            }
        }
    }
    template <class T>
    List<T>::~List() {
        for (int i = 0; i < mCount; i++) {
            get(i).~T();
        }
        delete[] buffer;
    }
    long benchmark(std::function<void()>);
    long benchmark(std::function<void()>, long);
    long benchmark(std::function<void()> f) {
        return benchmark(f, 100000);
    }
    long benchmark(std::function<void()> f, long iters) {
        using std::chrono::high_resolution_clock;
        using std::chrono::duration_cast;
        auto start = high_resolution_clock::now();
        for (long i = 0; i < iters; i++) {
            f();
        }
        auto end = high_resolution_clock::now();
        auto time = duration_cast<std::chrono::milliseconds>(end - start);
        return (long)time.count();
    }
}
#endif
test.cpp:
#include "dataset.hpp"
#include <iostream>
#include <vector>
/*
    TEST CODE
*/
class SimpleClass {
public:
    SimpleClass();
    SimpleClass(int);
    SimpleClass(const SimpleClass&);
    void sayHello();
    ~SimpleClass();
private:
    int data;
};
SimpleClass::SimpleClass() {
    //std::cout << "Constructed " << this << std::endl;
    data = 0;
}
SimpleClass::SimpleClass(int data) {
    //std::cout << "Constructed " << this << std::endl;
    this->data = data;
}
SimpleClass::SimpleClass(const SimpleClass& other) {
    //std::cout << "Copied to " << this << std::endl;
    data = other.data;
}
SimpleClass::~SimpleClass() {
    //std::cout << "Deconstructed " << this << std::endl;
}
void SimpleClass::sayHello() {
    std::cout << "Hello! I am #" << data << std::endl;
}
int main() {
    long list = Dataset::benchmark([]() {
        Dataset::List<SimpleClass> list = Dataset::List<SimpleClass>(1000);
        for (int i = 0; i < 1000; i++) {
            list.push(SimpleClass(i));
        }
    });
    long vec = Dataset::benchmark([]() {
        std::vector<SimpleClass> list = std::vector<SimpleClass>(1000);
        for (int i = 0; i < 1000; i++) {
            list.emplace_back(SimpleClass(i));
        }
    });
    std::cout << "List: " << list << "ms" << std::endl;
    std::cout << "Vector: " << vec << "ms" << std::endl;
    return 0;
}
 
     
    