#include <iostream>
#include <cassert>
#include <cstring>


template<typename T>
class stack {
public:
	stack(const size_t size = s_incrementSize) : m_index(-1) {
		assert(size > 0);
		m_memory = new T[size];
		m_size = size;
	}
	
	~stack() {
		for (size_t idx = 0; idx < m_index; ++idx) {
			m_memory[idx].~T();
		}
	}
	
	void push(const T &data) {
		if (++m_index >= m_size) {
			size_t newSize = m_size + s_incrementSize;
			T *newMemory = new T[newSize];
			memcpy(newMemory, m_memory, sizeof(T) * m_index);
			delete[] m_memory;
			m_memory = newMemory;
			m_size = newSize;
		}
		
		new (m_memory + m_index) T(data);
	}
	
	T pop() {
		if (m_index >= 0) {
			T result = m_memory[m_index];
			m_memory[m_index--].~T();
			return result;
		} else {
			return T();
		}
	}
	
	size_t size() const { return m_index + 1; }
	
	T &operator[](const size_t index) const {
		assert(index >= 0);
		assert(index <= m_index);
		
		return m_memory[index];
	}
	
private:
	static constexpr size_t s_incrementSize = 1000;

	size_t m_index;
	size_t m_size;
	T *m_memory;
};

int main(int argc, char **argv) {
	stack<int> s;
	
	s.push(10);
	s.push(20);
	s.push(30);
	
	while (s.size() > 0) {
		std::cout << " " << s.pop();
	}
	
	return 0;
}