#include <cstddef>

template <typename T>
class Array {
public:
    //   конструктор класса, который создает
    //   Array размера size, заполненный значениями
    //   value типа T. Считайте что у типа T есть
    //   конструктор, который можно вызвать без
    //   без параметров, либо он ему не нужен.
    //
    explicit Array(size_t size = 0, const T& value = T()) {
        this->table = static_cast<T*>(operator new[] (size * sizeof(T)));
        this->count = size;
        for (size_t i = 0; i < size; ++i) {
            //здесь память для объекта не выделяется, но инициализируется
            new (table + i) T(value);
        }
    }

    // Конструктор копирования, который создает
    // опию параметра. Считайте, что для типа
    // T определен оператор присваивания.
    //
    Array(const Array<T> &array) {
        this->table = static_cast<T*>(operator new[] (array.size() * sizeof(T)));
        this->count = array.size();
        for (size_t i = 0; i < count; ++i) {
            new (table + i) T(array[i]);
        }
    }

    // Деструктор, если он вам необходим.
    //
    ~Array() {
        for (size_t i = 0; i < count; ++i) {
            table[i].~T();
        }
        operator delete[] (table);
    }

    // Оператор присваивания.
    //
    Array& operator=(const Array<T> &array) {
        if (this != &array) {
            operator delete[] (table);
            /*this->table = new T[array.size()];
            this->count = array.size();
            for (size_t i = 0; i < count; ++i) {
                table[i] = array[i];
            }*/
            this->table = static_cast<T*>(operator new[] (array.size() * sizeof(T)));
            this->count = array.size();
            for (size_t i = 0; i < count; ++i) {
                //здесь память для объекта не выделяется, но инициализируется
                new (table + i) T(array[i]);
            }
        }
        return *this;
    }

    // Возвращает размер массива (количество элементов).
    //
    size_t size() const {
        return count;
    }

    // const T& operator[](size_t) const
    //   две версии оператора доступа по индексу.
    T& operator[](size_t index) {
        return table[index];
    }

    T operator[](size_t index) const {
        return table[index];
    }

private:
    T* table;
    size_t count;
};