一、測試程序
#ifndef MYTINYSTL_VECTOR_TEST_H_
#define MYTINYSTL_VECTOR_TEST_H_
// vector test : 測試 vector 的接口與 push_back 的性能
#include <vector>
#include "../MyTinySTL/vector.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace vector_test
{
void vector_test()
{
std::cout << "[===============================================================]\n";
std::cout << "[----------------- Run container test : vector -----------------]\n";
std::cout << "[-------------------------- API test ---------------------------]\n";
int a[] = { 1,2,3,4,5 };
mystl::vector<int> v1;
mystl::vector<int> v2(10);
mystl::vector<int> v3(10, 1);
mystl::vector<int> v4(a, a + 5);
mystl::vector<int> v5(v2);
mystl::vector<int> v6(std::move(v2));
mystl::vector<int> v7{ 1,2,3,4,5,6,7,8,9 };
mystl::vector<int> v8, v9, v10;
v8 = v3;
v9 = std::move(v3);
v10 = { 1,2,3,4,5,6,7,8,9 };
FUN_AFTER(v1, v1.assign(8, 8));
FUN_AFTER(v1, v1.assign(a, a + 5));
FUN_AFTER(v1, v1.emplace(v1.begin(), 0));
FUN_AFTER(v1, v1.emplace_back(6));
FUN_AFTER(v1, v1.push_back(6));
FUN_AFTER(v1, v1.insert(v1.end(), 7));
FUN_AFTER(v1, v1.insert(v1.begin() + 3, 2, 3));
FUN_AFTER(v1, v1.insert(v1.begin(), a, a + 5));
FUN_AFTER(v1, v1.pop_back());
FUN_AFTER(v1, v1.erase(v1.begin()));
FUN_AFTER(v1, v1.erase(v1.begin(), v1.begin() + 2));
FUN_AFTER(v1, v1.reverse());
FUN_AFTER(v1, v1.swap(v4));
FUN_VALUE(*v1.begin());
FUN_VALUE(*(v1.end() - 1));
FUN_VALUE(*v1.rbegin());
FUN_VALUE(*(v1.rend() - 1));
FUN_VALUE(v1.front());
FUN_VALUE(v1.back());
FUN_VALUE(v1[0]);
FUN_VALUE(v1.at(1));
int* p = v1.data();
*p = 10;
*++p = 20;
p[1] = 30;
std::cout << " After change v1.data() :" << "\n";
COUT(v1);
std::cout << std::boolalpha;
FUN_VALUE(v1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(v1.size());
FUN_VALUE(v1.max_size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.resize(10));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.resize(6, 6));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.clear());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.reserve(5));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.reserve(20));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]\n";
std::cout << "|---------------------|-------------|-------------|-------------|\n";
std::cout << "| push_back |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(vector<int>, push_back, rand(), LEN1 _LL, LEN2 _LL, LEN3 _LL);
#else
CON_TEST_P1(vector<int>, push_back, rand(), LEN1 _L, LEN2 _L, LEN3 _L);
#endif
std::cout << "\n";
std::cout << "|---------------------|-------------|-------------|-------------|\n";
PASSED;
#endif
std::cout << "[----------------- End container test : vector -----------------]\n";
}
} // namespace vector_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_VECTOR_TEST_H_
首先測試文件定義了兩個常用的宏:FUN_AFTER和FUN_VALUE
// 輸出容器調用函數後的結果
#define FUN_AFTER(con, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
COUT(con); \
} while(0)
// 遍歷輸出容器
#define COUT(container) do { \
std::string con_name = #container; \
std::cout << " " << con_name << " :"; \
for (auto it : container) \
std::cout << " " << it; \
std::cout << "\n"; \
} while(0)
// 輸出容器調用函數的值
#define FUN_VALUE(fun) do { \
std::string fun_name = #fun; \
std::cout << " " << fun_name << " : " << fun << "\n"; \
} while(0)
還定義了一個性能測試相關的宏CON_TEST_P1
//std表示使用std定義的容器執行操作所耗費的時間
//mystl表示使用自定義的容器執行操作所耗費的時間
#define CON_TEST_P1(con, fun, arg, len1, len2, len3) \
TEST_LEN(len1, len2, len3, WIDE); \
std::cout << "| std |"; \
FUN_TEST_FORMAT1(std::con, fun, arg, len1); \
FUN_TEST_FORMAT1(std::con, fun, arg, len2); \
FUN_TEST_FORMAT1(std::con, fun, arg, len3); \
std::cout << "\n| mystl |"; \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len1); \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len2); \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len3);
#define TEST_LEN(len1, len2, len3, wide) \
test_len(len1, len2, len3, wide)
// 輸出測試數量級
void test_len(size_t len1, size_t len2, size_t len3, size_t wide)
{
std::string str1, str2, str3;
std::stringstream ss;
ss << len1 << " " << len2 << " " << len3;
ss >> str1 >> str2 >> str3;
str1 += " |";
std::cout << std::setw(wide) << str1;
str2 += " |";
std::cout << std::setw(wide) << str2;
str3 += " |";
std::cout << std::setw(wide) << str3 << "\n";
}
// 常用測試性能的宏
#define FUN_TEST_FORMAT1(mode, fun, arg, count) do { \
srand((int)time(0)); \
clock_t start, end; \
mode c; \
char buf[10]; \
start = clock(); \
for (size_t i = 0; i < count; ++i) \
c.fun(arg); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
} while(0)
二、測試程序解析
2.1.初始化
2.1.1無參構造函數
vector() noexcept
{ try_init(); }
// try_init 函數,若分配失敗則忽略,不拋出異常
template <class T>
void vector<T>::try_init() noexcept//函數聲明時也不能缺少noexcept
{
try
{
begin_ = data_allocator::allocate(16);//默認分配16個元素空間,begin_指向已使用空間的開頭
end_ = begin_;//end_指向已使用空間的尾部
cap_ = begin_ + 16;//cap_指向總分配空間的尾部,這裏+16,而不是+16*sizeof(T),因爲指針移動是依據數據類型大小
}
catch (...)
{
begin_ = nullptr;
end_ = nullptr;
cap_ = nullptr;
}
}
typedef mystl::allocator<T> data_allocator;
template <class T>
T* allocator<T>::allocate(size_type n)//typedef size_t size_type;
{
if (n == 0)
return nullptr;
return static_cast<T*>(::operator new(n * sizeof(T)));
}
2.1.2有參構造函數
explicit vector(size_type n)
{ fill_init(n, value_type()); }
vector(size_type n, const value_type& value)
{ fill_init(n, value); }
template <class T>
void vector<T>::fill_init(size_type n, const value_type& value)
{
const size_type init_size = mystl::max(static_cast<size_type>(16), n);
init_space(n, init_size);
mystl::uninitialized_fill_n(begin_, n, value);//從begin_位置填充n個value
}
template <class T>
void vector<T>::init_space(size_type size, size_type cap)
{
try
{
begin_ = data_allocator::allocate(cap);
end_ = begin_ + size;
cap_ = begin_ + cap;
}
catch (...)
{
begin_ = nullptr;
end_ = nullptr;
cap_ = nullptr;
throw;
}
}
typedef typename allocator_type::value_type value_type;
typedef mystl::allocator<T> allocator_type;
typedef T value_type;
2.1.3迭代器範圍初始化
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
vector(Iter first, Iter last)
{
MYSTL_DEBUG(!(last < first));
range_init(first, last);
}
template <class T>
template <class Iter>
void vector<T>::range_init(Iter first, Iter last)
{
const size_type init_size = mystl::max(static_cast<size_type>(last - first),
static_cast<size_type>(16));
init_space(static_cast<size_type>(last - first), init_size);
mystl::uninitialized_copy(first, last, begin_);//將first至last範圍內的元素拷貝到begin_處
}
2.1.4拷貝構造函數
vector(const vector& rhs)
{
range_init(rhs.begin_, rhs.end_);
}
2.1.5移動構造函數
vector(vector&& rhs) noexcept//僅僅是指針的賦值,並沒有申請內存,並且把右值的指針置空
:begin_(rhs.begin_),
end_(rhs.end_),
cap_(rhs.cap_)
{
rhs.begin_ = nullptr;
rhs.end_ = nullptr;
rhs.cap_ = nullptr;
}
2.1.6初始化列表初始化
vector(std::initializer_list<value_type> ilist)
{
range_init(ilist.begin(), ilist.end());
}
2.2賦值
2.2.1常引用賦值
template <class T>
vector<T>& vector<T>::operator=(const vector& rhs)
{
if (this != &rhs)//不處理自己給自己賦值
{
const auto len = rhs.size();
if (len > capacity())//當前vector容量不夠,就需要擴容
{
vector tmp(rhs.begin(), rhs.end());
swap(tmp);//this和另一個vector互換
}
else if (size() >= len)//當前vector內容比rhs長,需要將當前vector多餘的內容銷燬
{
auto i = mystl::copy(rhs.begin(), rhs.end(), begin());
data_allocator::destroy(i, end_);//刪除範圍內的元素,但並不會釋放空間
end_ = begin_ + len;
}
else
{
mystl::copy(rhs.begin(), rhs.begin() + size(), begin_);
mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_);//將多餘部分置零
cap_ = end_ = begin_ + len;
}
}
return *this;
}
2.2.2移動賦值
template <class T>
vector<T>& vector<T>::operator=(vector&& rhs) noexcept
{
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = rhs.begin_;
end_ = rhs.end_;
cap_ = rhs.cap_;
rhs.begin_ = nullptr;
rhs.end_ = nullptr;
rhs.cap_ = nullptr;
return *this;
}
template <class T>
void vector<T>::
destroy_and_recover(iterator first, iterator last, size_type n)
{
data_allocator::destroy(first, last);//刪除範圍內的元素,但並不會釋放空間
data_allocator::deallocate(first, n);//釋放空間
}
2.2.3初始化列表賦值
vector& operator=(std::initializer_list<value_type> ilist)
{
vector tmp(ilist.begin(), ilist.end());
swap(tmp);
return *this;
}
2.3析構函數
~vector()
{
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = end_ = cap_ = nullptr;
}
三、常用函數
3.1迭代器相關函數
iterator begin() noexcept
{ return begin_; }
const_iterator begin() const noexcept
{ return begin_; }
iterator end() noexcept
{ return end_; }
const_iterator end() const noexcept
{ return end_; }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
typedef mystl::reverse_iterator<iterator> reverse_iterator;
typedef mystl::reverse_iterator<const_iterator> const_reverse_iterator;
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
3.2容量相關函數
bool empty() const noexcept
{ return begin_ == end_; }
size_type size() const noexcept
{ return static_cast<size_type>(end_ - begin_); }
size_type max_size() const noexcept
{ return static_cast<size_type>(-1) / sizeof(T); }
size_type capacity() const noexcept
{ return static_cast<size_type>(cap_ - begin_); }
// 預留空間大小,當原容量小於要求大小時,纔會重新分配
template <class T>
void vector<T>::reserve(size_type n)
{
if (capacity() < n)
{
THROW_LENGTH_ERROR_IF(n > max_size(),
"n can not larger than max_size() in vector<T>::reserve(n)");
const auto old_size = size();
auto tmp = data_allocator::allocate(n);
mystl::uninitialized_move(begin_, end_, tmp);
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = tmp;
end_ = tmp + old_size;
cap_ = begin_ + n;
}
}
// 放棄多餘的容量
template <class T>
void vector<T>::shrink_to_fit()
{
if (end_ < cap_)
{
reinsert(size());
}
}
template <class T>
void vector<T>::reinsert(size_type size)
{
auto new_begin = data_allocator::allocate(size);
try
{
mystl::uninitialized_move(begin_, end_, new_begin);
}
catch (...)
{
data_allocator::deallocate(new_begin, size);
throw;
}
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = new_begin;
end_ = begin_ + size;
cap_ = begin_ + size;
}
3.3元素訪問相關函數
reference operator[](size_type n)
{
MYSTL_DEBUG(n < size());
return *(begin_ + n);
}
typedef typename allocator_type::reference reference;
typedef mystl::allocator<T> allocator_type;
typedef T& reference;
const_reference operator[](size_type n) const
{
MYSTL_DEBUG(n < size());
return *(begin_ + n);
}
reference at(size_type n)
{
THROW_OUT_OF_RANGE_IF(!(n < size()), "vector<T>::at() subscript out of range");
return (*this)[n];
}
const_reference at(size_type n) const
{
THROW_OUT_OF_RANGE_IF(!(n < size()), "vector<T>::at() subscript out of range");
return (*this)[n];
}
reference front()
{
MYSTL_DEBUG(!empty());
return *begin_;
}
const_reference front() const
{
MYSTL_DEBUG(!empty());
return *begin_;
}
reference back()
{
MYSTL_DEBUG(!empty());
return *(end_ - 1);
}
const_reference back() const
{
MYSTL_DEBUG(!empty());
return *(end_ - 1);
}
pointer data() noexcept { return begin_; }
typedef typename allocator_type::pointer pointer;
typedef mystl::allocator<T> allocator_type;
typedef T* pointer;
const_pointer data() const noexcept { return begin_; }
3.4修改容器相關函數
// assign將vector賦值爲n個value
void assign(size_type n, const value_type& value)
{ fill_assign(n, value); }
template <class T>
void vector<T>::fill_assign(size_type n, const value_type& value)
{
if (n > capacity())
{
vector tmp(n, value);
swap(tmp);
}
else if (n > size())
{
mystl::fill(begin(), end(), value);
end_ = mystl::uninitialized_fill_n(end_, n - size(), value);
}
else
{
//刪除末尾多出來的內容
erase(mystl::fill_n(begin_, n, value), end_);
}
}
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
void assign(Iter first, Iter last)
{
MYSTL_DEBUG(!(last < first));
copy_assign(first, last, iterator_category(first));
}
template <class T>
template <class IIter>
void vector<T>::copy_assign(IIter first, IIter last, input_iterator_tag)
{
auto cur = begin_;
for (; first != last && cur != end_; ++first, ++cur)
{
*cur = *first;
}
if (first == last)//如果size比迭代器範圍大,說明後面還又內容,應該刪掉
{
erase(cur, end_);
}
else//繼續複製迭代器範圍內的元素
{
insert(end_, first, last);
}
}
void assign(std::initializer_list<value_type> il)
{ copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag{}); }
// emplace / emplace_back
// 在 pos 位置就地構造元素,避免額外的複製或移動開銷
//將參數傳遞給T的構造函數,而不是包含參數的對象,emplace使用這些參數在內存空間中直接構造元素
template <class T>
template <class ...Args>
typename vector<T>::iterator
vector<T>::emplace(const_iterator pos, Args&& ...args)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
iterator xpos = const_cast<iterator>(pos);//去const
const size_type n = xpos - begin_;
if (end_ != cap_ && xpos == end_)//在vecotr末尾插入,相當於emplace_back
{
data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);
++end_;
}
else if (end_ != cap_)//還有未使用空間
{
auto new_end = end_;
data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));
++new_end;
mystl::copy_backward(xpos, end_ - 1, end_);//emplace同樣有數據搬運的操作
*xpos = value_type(mystl::forward<Args>(args)...);
}
else//如果空間不夠則重新分配空間,並在 pos 處就地構造元素
{
reallocate_emplace(xpos, mystl::forward<Args>(args)...);
}
return begin() + n;
}
// 在尾部就地構造元素,避免額外的複製或移動開銷
template <class T>
template <class ...Args>
void vector<T>::emplace_back(Args&& ...args)
{
if (end_ < cap_)
{
data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);
++end_;
}
else
{
reallocate_emplace(end_, mystl::forward<Args>(args)...);
}
}
// push_back / pop_back
// 在尾部插入元素
template <class T>
void vector<T>::push_back(const value_type& value)
{
if (end_ != cap_)
{
data_allocator::construct(mystl::address_of(*end_), value);
++end_;
}
else
{
reallocate_insert(end_, value);
}
}
void push_back(value_type&& value)
{ emplace_back(mystl::move(value)); }
// 彈出尾部元素
template <class T>
void vector<T>::pop_back()
{
MYSTL_DEBUG(!empty());
data_allocator::destroy(end_ - 1);
--end_;
}
// emplace和insert相比,只是因爲傳參而不是傳對象,所以少了構建一次臨時對象的步驟
template <class T>
typename vector<T>::iterator vector<T>::insert(const_iterator pos, const value_type& value)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
iterator xpos = const_cast<iterator>(pos);
const size_type n = pos - begin_;
if (end_ != cap_ && xpos == end_)
{
data_allocator::construct(mystl::address_of(*end_), value);
++end_;
}
else if (end_ != cap_)
{
auto new_end = end_;
data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));
++new_end;
auto value_copy = value; // 避免元素因以下複製操作而被改變
mystl::copy_backward(xpos, end_ - 1, end_);
*xpos = mystl::move(value_copy);
}
else
{
reallocate_insert(xpos, value);
}
return begin_ + n;
}
iterator insert(const_iterator pos, value_type&& value)
{ return emplace(pos, mystl::move(value)); }
iterator insert(const_iterator pos, size_type n, const value_type& value)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
return fill_insert(const_cast<iterator>(pos), n, value);
}
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
void insert(const_iterator pos, Iter first, Iter last)
{
MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first));
copy_insert(const_cast<iterator>(pos), first, last);
}
// erase / clear
template <class T>
typename vector<T>::iterator
vector<T>::erase(const_iterator pos)
{
MYSTL_DEBUG(pos >= begin() && pos < end());
iterator xpos = begin_ + (pos - begin());
mystl::move(xpos + 1, end_, xpos);
data_allocator::destroy(end_ - 1);
--end_;
return xpos;
}
template <class T>
typename vector<T>::iterator
vector<T>::erase(const_iterator first, const_iterator last)
{
MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first));
const auto n = first - begin();
iterator r = begin_ + (first - begin());
data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_);
end_ = end_ - (last - first);
return begin_ + n;
}
void clear() { erase(begin(), end()); }
// resize / reverse
void resize(size_type new_size) { return resize(new_size, value_type()); }
template <class T>
void vector<T>::resize(size_type new_size, const value_type& value)
{
if (new_size < size())//截斷
{
erase(begin() + new_size, end());
}
else
{
insert(end(), new_size - size(), value);
}
}
void reverse() { mystl::reverse(begin(), end()); }
// swap
template <class T>
void vector<T>::swap(vector<T>& rhs) noexcept
{
if (this != &rhs)
{
mystl::swap(begin_, rhs.begin_);
mystl::swap(end_, rhs.end_);
mystl::swap(cap_, rhs.cap_);
}
}
3.5重載比較運算符
template <class T>
bool operator==(const vector<T>& lhs, const vector<T>& rhs)
{
return lhs.size() == rhs.size() &&
mystl::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <class T>
bool operator<(const vector<T>& lhs, const vector<T>& rhs)
{
return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), lhs.end());
}
template <class T>
bool operator!=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(lhs == rhs);
}
template <class T>
bool operator>(const vector<T>& lhs, const vector<T>& rhs)
{
return rhs < lhs;
}
template <class T>
bool operator<=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(rhs < lhs);
}
template <class T>
bool operator>=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(lhs < rhs);
}
// 重載 mystl 的 swap
template <class T>
void swap(vector<T>& lhs, vector<T>& rhs)
{
lhs.swap(rhs);
}