# Custom vector, part 2

In [Custom vector, part 1](/_/cpp/memory/vector-arraylist/custom-vector-part-1.md), we have created a vector class that will add any new element and resize to any limit (at least till your app goes out of memory).

Now, lets try it with a class object, which will store elements on heap, here we can track added items constructor/deconstructor calls.

Here, we have created a wrapper class on `int`, where it will keep hold for a integer value.

We have overridden multiple constructors and deconstructors, we log these events to understand more of what happens internally.

```cpp
#include <iostream>

class MyInt {
private:
    int _int;

public:
    MyInt() : _int(0) {
        std::cout << "Default Constructor called for " << _int << ", address: " << &_int << std::endl;
    }

    MyInt(int a) : _int(a) {
        std::cout << "Constructor called for " << _int << ", address: " << &_int << std::endl;
    }

    ~MyInt() {
        std::cout << "Deconstructor called for " << _int << ", address: " << &_int << std::endl;
    }

    // Copy constructor
    MyInt(const MyInt& other): _int(other._int) {
        std::cout << "Copy constructor called for " << _int << ", address: " << &_int << std::endl;
    }

    // Move constructor
    MyInt(MyInt&& other) noexcept : _int(other._int) {
        std::cout << "Move constructor called for " << _int << ", address: " << &_int << std::endl;
    }

    void introduce() const {
        std::cout << "MyInt Value:  " << _int << ", address: " << &_int << std::endl;
    }

    MyInt& operator=(const MyInt& other) {
        if (this != &other) {
            _int = other._int;
        }
        return *this;
    }

    friend std::ostream& operator<<(std::ostream& os, const MyInt& obj);
};

std::ostream& operator<<(std::ostream& os, const MyInt& obj) {
    os << "value: " << obj._int;
    return os;
}

template <typename T>
class MyVector {
public:
    MyVector() : _data(nullptr), _size(0), capacity(0) {}

    ~MyVector() {
        delete[] _data;
    }

    void push_back(const T& value) {
        if (_size == capacity) {
            resize();
        }
        _data[_size++] = value;
    }

    void pop_back() {
        if (_size > 0) {
            --_size;
        }
    }

    T& operator[](size_t index) {
        return _data[index];
    }

    const T& operator[](size_t index) const {
        return _data[index];
    }

    size_t size() const {
        return _size;
    }

private:
    T* _data;
    size_t _size;
    size_t capacity;

    void resize() {
        capacity = capacity == 0 ? 1 : capacity * 2;
        T* new_data = new T[capacity];
        for (size_t i = 0; i < _size; ++i) {
            new_data[i] = _data[i];
        }
        delete[] _data;
        _data = new_data;
    }
};

int main() {
    MyVector<MyInt> v;
    std::cout << "add fist" << std::endl;
    v.push_back(MyInt(35));
    
    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "value: " << v[i] << ", address: " << &v[i] << std::endl;
    }
    
    std::cout << "add second" << std::endl;
    v.push_back(MyInt(30));
    
    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "value: " << v[i] << ", address: " << &v[i] << std::endl;
    }
    
    std::cout << "add third" << std::endl;
    v.push_back(MyInt(25));

    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "value: " << v[i] << ", address: " << &v[i] << std::endl;
    }

    std::cout << "pop back" << std::endl;
    v.pop_back();

    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "value: " << v[i] << ", address: " << &v[i] << std::endl;
    }
    
    std::cout << "add fourth" << std::endl;
    v.push_back(MyInt(20));

    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "value: " << v[i] << ", address: " << &v[i] << std::endl;
    }

    return 0;
}
```

#### Output:

```
add fist
Constructor called for 35, address: 0x7ffd588620c4
Default Constructor called for 0, address: 0x560e071ddec8
Deconstructor called for 35, address: 0x7ffd588620c4
value: value: 35, address: 0x560e071ddec8
add second
Constructor called for 30, address: 0x7ffd588620c4
Default Constructor called for 0, address: 0x560e071ddee8
Default Constructor called for 0, address: 0x560e071ddeec
Deconstructor called for 35, address: 0x560e071ddec8
Deconstructor called for 30, address: 0x7ffd588620c4
value: value: 35, address: 0x560e071ddee8
value: value: 30, address: 0x560e071ddeec
add third
Constructor called for 25, address: 0x7ffd588620c4
Default Constructor called for 0, address: 0x560e071ddec8
Default Constructor called for 0, address: 0x560e071ddecc
Default Constructor called for 0, address: 0x560e071dded0
Default Constructor called for 0, address: 0x560e071dded4
Deconstructor called for 30, address: 0x560e071ddeec
Deconstructor called for 35, address: 0x560e071ddee8
Deconstructor called for 25, address: 0x7ffd588620c4
value: value: 35, address: 0x560e071ddec8
value: value: 30, address: 0x560e071ddecc
value: value: 25, address: 0x560e071dded0
pop back
value: value: 35, address: 0x560e071ddec8
value: value: 30, address: 0x560e071ddecc
add fourth
Constructor called for 20, address: 0x7ffd588620c4
Deconstructor called for 20, address: 0x7ffd588620c4
value: value: 35, address: 0x560e071ddec8
value: value: 30, address: 0x560e071ddecc
value: value: 20, address: 0x560e071dded0
Deconstructor called for 0, address: 0x560e071dded4
Deconstructor called for 20, address: 0x560e071dded0
Deconstructor called for 30, address: 0x560e071ddecc
Deconstructor called for 35, address: 0x560e071ddec8
```

Here, lets look at the output:

As we look at the logs,&#x20;

1. We create a new object using Parameterised Constructor.
2. Then we check if `size == capacity`, here it comes yes.
3. Now we create an array of size 1, filled with default object.
4. After creating new array, we call default constructor to create a new object to fill it initially.
5. Then, we copy all elements from previous array to new array with increased size.
6. After copying old array, now we can delete it from memory as all elements are safe in new array.
7. Repeat `2` to `6` till we have added all elements.

As we see, we do a lot of memory operations for storing new data into vector.

Here are steps for each cycle:

1. Create multiple objects.
2. Copy them to new memory location.
3. Delete old data.

This consume precious memory and CPU cycle for simple operations, in next lesson, we will see how we can optimise this.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.tejpratapsingh.com/_/cpp/memory/vector-arraylist/custom-vector-part-2.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
