11-2 實作 Vec 的細節

一、建構與解構函數
在建構函數中，我們要初始化 Vec 的 data member。因為剛建立好的 Vec 會是一個空的容器，所以一開始 m_size 和 m_capacity 都是 0。而 m_data 則先賦予它 nullptr 值，表示目前沒有指向任何記憶體。
Vec::Vec()
{
 m_data = nullptr;
 m_size = 0;
 m_capacity = 0;
}

在解構函數部分，我們先檢查是不有向作業系統要求配置記憶體，若有的話 m_data 將不會是 nullptr，而是會指向那塊記憶體。我們要釋放配置的記憶，把它還給作業系統。
Vec::~Vec()
{
 if(m_data!=nullptr)
 {
 delete [] m_data;
 }
}

二、size 和 capacity
Vec 的 size 和 capacity 會隨著 push_back 放入愈來愈多的元素而成長，這兩個 data member 不應該被使用者修改，所以我們只提供兩個相應的成員函數用來回傳其值。
int Vec::size()
{
 return m_size;
}

int Vec::capacity()
{
 return m_capacity;
}

三、push_back
在 Vec 空間需要成長時，我們採用一個簡單的策略 - 每次成長為之前的 2倍大。
要留意的是，由於一開始 capacity 是 0，乘以 2 之後還是 0，所以要特別處理這個狀況，在第一次 push_back 時，capacity 要成長為 1。
在成長的部分，流程如下。

配置一塊原來 2 倍大的記憶體空間
把舊資料搬到新空間
釋放舊空間記憶體，還給作業系統
將 m_data 指向新的這塊記憶體

void Vec::push_back(int val)
{
 // 如果空間不夠用
 if(m_size==m_capacity)
 {
 // 每次成長為原來的 2 倍大小
 int new_capacity = m_capacity*2;

 if(new_capacity==0)
 new_capacity = 1;

 // 配置一塊新的空間
 int *new_data = new int[new_capacity];
 // 把資料搬到新的空間
 for(int i=0; i<m_size; i++)
 {
 new_data[i] = m_data[i];
 }
 // 釋放舊的空間，改用新空間
 if(m_data!=nullptr)
 delete [] m_data;

 m_data = new_data;
 m_capacity = new_capacity;
 }

 m_data[m_size] = val;
 m_size++;
}

四、pop_back()
pop_back 部分很簡單，只要把 size - 1 即可，不必清除那塊記憶體。下次 push_back 時，新資料就會蓋掉它。
void Vec::pop_back()
{
 m_size--;
}

