2.4 Vector<T> 动态数组(随机访问迭代器)

C++自学精简教程 目录(必读)

该 Vector 版本特点

这里的版本主要是使用模板实现、支持随机访问迭代器,支持std::sort等所有STL算法。(本文对随机迭代器的支持参考了 复旦大学 大一公共基础课C++语言的一次作业)

随机访问迭代器的实现主要是继承std::iterator<std::random_access_iterator_tag, T>来实现的。

随机访问迭代器最牛逼的两个接口是:

friend iterator operator+(const iterator& lhs, size_t n);

friend iterator operator-(const iterator& lhs, size_t n);

问题解答

1 为何下面代码中的iterator是struct而不是class?

答:参考struct与class

完整代码

#include <iostream>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <initializer_list>
// >>>>>>>>>>>>> do not care the code about memory leak checking. begin <<<<<<<<<<<<<<<
#include <iostream>
#include <cassert>
using namespace std;
struct MemoryNode{
    void* ptr = 0;
    bool m_released = false;
    size_t byte_count = 0;
    char file[100] = { 0 };
    int line = -1;
    bool is_array = false;
    MemoryNode* next = nullptr;
};
struct MemoryList{
    ~MemoryList(){
        bool exist_leak = false;
        auto temp = head.next;
        while (temp){
            if (temp->m_released == false){
                cout << "memory leak " << temp->byte_count << " byte(s) !!!" << endl;
                exist_leak = true;
            }
            temp = temp->next;
        }
        if (!exist_leak){
            cout << "OK good job ! No memory leak." << endl;
        }
    }
    static MemoryNode* C_NewNode(void* ptr, size_t size, const char* file, int line, bool is_array){
        auto pnode = (MemoryNode*)malloc(sizeof(MemoryNode));
        pnode->ptr = ptr;
        pnode->m_released = false;
        pnode->byte_count = size;
        for (char* p = pnode->file; *file != '\0'; p++, file++) {*p = *file;}
        pnode->line = line;
        pnode->is_array = is_array;
        pnode->next = nullptr;
        return pnode;
    }
    void push_back(MemoryNode* pnode){
        if (tail == nullptr){
            head.next = tail = pnode;
        }else{
            tail->next = pnode;
            tail = tail->next;
        }
        ++m_size;
    }
    MemoryNode* find(void* ptr){
        auto temp = head.next;
        while (temp){
            if (temp->ptr == ptr){
                return temp;
            }
            temp = temp->next;
        }
        return nullptr;
    }
private:
    int m_size = 0;
    MemoryNode head;
    MemoryNode* tail = nullptr;
};
static MemoryList g_MemoryList;
void* operator new(size_t size, char const* file, int line){
    void* ptr = malloc(size);
    auto pnode = MemoryList::C_NewNode(ptr, size, file, line, false);
    g_MemoryList.push_back(pnode);
    return ptr;
}
void* operator new[](std::size_t size, char const* file, int line){
    void* ptr = malloc(size);
    auto pnode = MemoryList::C_NewNode(ptr, size, file, line, true);
    g_MemoryList.push_back(pnode);
    return ptr;
}
void operator delete(void* ptr) noexcept{
    if (ptr == nullptr)
    {
        cout << "can not delete nullptr !!!" << endl;
        assert(false);
    }
    auto node = g_MemoryList.find(ptr);
    if (node == nullptr){
        cout << "you want to free memory which is not allocated from new !!!" << endl;
        assert(false);
    }
    else
    {
        if (node->is_array){
            cout << "momory allocated at line " << node->line << ", you want to free memory by delete not delete[] which is allocatd from new[] !!!" << endl;
            assert(false);
        }
        if (node->m_released){
            cout << "momory allocated at line " << node->line << ", you want to free one memory twice !!!" << endl;
            assert(false);
        }
        node->m_released = true;
    }
}

void operator delete[](void* ptr) noexcept{
    if (ptr == nullptr)
    {
        cout << "can not delete nullptr !!!" << endl;
        assert(false);
    }
    auto node = g_MemoryList.find(ptr);
    if (node == nullptr){
        cout << "you want to free memory which is not allocated from new !!!" << endl;
        assert(false);
    }
    else{
        if (!node->is_array){
            cout << "momory allocated at line " << node->line << ", you want to free memory by delete[] not delete which is allocatd from new !!!" << endl;
            assert(false);
        }
        if (node->m_released){
            cout << "momory allocated at line " << node->line << ", you want to free one memory twice !!!" << endl;
            assert(false);
        }
        node->m_released = true;
    }
}
void operator delete(void* pMem, const char* pszFilename, int nLine){ //msvc need
    cout << (int*)pMem << pszFilename << nLine << endl;
    free(pMem);
    assert(false);
}
void operator delete[](void* pMem, const char* pszFilename, int nLine){ //msvc need
    cout << (int*)pMem << pszFilename << nLine << endl;
    free(pMem);
    assert(false);
}
void operator delete(void*, std::size_t)//Ubuntu need
{
	assert(false);
}
//void operator delete[](void*, std::size_t)//Ubuntu need
//{
//	assert(false);
//}
#define new new(__FILE__, __LINE__)
void check_do(bool b, int line = __LINE__) { if (b) { cout << "line:" << line << " Pass" << endl; } else { cout << "line:" << line << " Ohh! not passed!!!!!!!!!!!!!!!!!!!!!!!!!!!" << " " << endl; exit(0); } }
#define check(msg)  check_do(msg, __LINE__);
// >>>>>>>>>>>>> do not care the code about memory leak checking. begin <<<<<<<<<<<<<<<

template<typename T>
class Vector
{
public:
	/* default constructor for the following code :
		Vector<int> arr;
	*/
	Vector(void)
	{
		cout << "Vector(void)" << endl;
	}
	Vector(const Vector& from);//copy constructor
	Vector(T* start, T* end);//constructor
	Vector(int count, T value);//constructor
	Vector(std::initializer_list<T> value_array)
	{
		for (auto& item : value_array)
		{
			push_back(item);//use push_back to make code simple
		}
	}
	Vector& operator = (const Vector& from);// deep copy please
	bool operator==(const Vector& other) const // the same length and every element is the samae
	{
		//(1) your code . you have to modify the following code
		return other.m_data[0] == this->m_data[0];
	}
	bool operator!=(const Vector& other) const// use operator == for this function
	{
		return !(*this == other);
	}
	~Vector();//destructor
public:
	int size(void) const;
	bool empty(void) const;
	T& operator[] (int n) const;
	T& operator[] (int n);
	void push_back(const T& val);
	void clear(void);
private:
	void deep_copy_from(const Vector<T>& from);

public:
	struct iterator : std::iterator<std::random_access_iterator_tag, T>
	{
		friend class  Vector;
		friend bool operator == (const iterator& lhs, const iterator& rhs) { return lhs.m_hold == rhs.m_hold; }
		friend bool operator != (const iterator& lhs, const iterator& rhs) { return !(lhs == rhs); }
		friend size_t operator - (const iterator& lhs, const iterator& rhs) { return lhs.m_hold - rhs.m_hold; }
		friend bool operator < (const iterator& lhs, const iterator& rhs) { return lhs.m_hold < rhs.m_hold; }
		friend bool operator > (const iterator& lhs, const iterator& rhs) { return lhs.m_hold > rhs.m_hold; }
		friend bool operator <= (const iterator& lhs, const iterator& rhs) { return !(lhs > rhs); }
		friend bool operator >= (const iterator& lhs, const iterator& rhs) { return !(lhs < rhs); }
		friend iterator operator + (const iterator& lhs, size_t n) { iterator itr; itr.m_hold = lhs.m_hold + n; return itr; }//随机访问迭代器牛逼的地方
		friend iterator operator - (const iterator& lhs, size_t n) { iterator itr; itr.m_hold = lhs.m_hold - n; return itr; }//随机访问迭代器牛逼的地方
	public:
		//for ++itr
		iterator& operator++() { m_hold = m_hold + 1; return *this; };
		iterator& operator--() { m_hold = m_hold - 1; return *this; };
		//for itr++
		iterator operator++(int) { iterator itr = *this; m_hold += 1; return itr; }
		iterator operator--(int) { iterator itr = *this; m_hold -= 1; return itr; }
		T& operator*() const//here must const in C++14
		{
			return *m_hold;
		}
	private:
		T* m_hold;
	};
	struct const_iterator : std::iterator<std::random_access_iterator_tag, T>
	{
		friend class  Vector;
		friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) { return lhs.m_hold == rhs.m_hold; }
		friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) { return !(lhs == rhs); }
		friend size_t operator - (const const_iterator& lhs, const const_iterator& rhs) { return lhs.m_hold - rhs.m_hold; }
		friend bool operator < (const const_iterator& lhs, const const_iterator& rhs) { return lhs.m_hold < rhs.m_hold; }
		friend bool operator > (const const_iterator& lhs, const const_iterator& rhs) { return lhs.m_hold > rhs.m_hold; }
		friend bool operator <= (const const_iterator& lhs, const const_iterator& rhs) { return !(lhs > rhs); }
		friend bool operator >= (const const_iterator& lhs, const const_iterator& rhs) { return !(lhs < rhs); }
		friend const_iterator operator + (const const_iterator& lhs, size_t n) { const_iterator itr; itr.m_hold = lhs.m_hold + n; return itr; }//随机访问迭代器牛逼的地方
		friend const_iterator operator - (const const_iterator& lhs, size_t n) { const_iterator itr; itr.m_hold = lhs.m_hold - n; return itr; }//随机访问迭代器牛逼的地方
	public:
		//for ++itr
		const_iterator& operator++() { m_hold = m_hold + 1; return *this; };
		const_iterator& operator--() { m_hold = m_hold - 1; return *this; };
		//for itr++
		const_iterator operator++(int) { const_iterator itr = *this; m_hold += 1; return itr; }
		const_iterator operator--(int) { const_iterator itr = *this; m_hold -= 1; return itr; }
		const T& operator*() const
		{
			return *m_hold;
		}
	private:
		T* m_hold;
	};

	iterator begin() noexcept
	{
		iterator itr;
		itr.m_hold = empty() ? nullptr : &m_data[0];
		return itr;
	}
	const_iterator cbegin() const noexcept;
	iterator end() noexcept
	{
		iterator itr;
		itr.m_hold = empty() ? nullptr : &m_data[m_size];
		return itr;
	}
	const_iterator cend() const noexcept;
private:
	int m_size = 0;//count element 
	int m_capacity = 0;//element count + space for push_back
	T* m_data = nullptr;//array for hold data
};

template<typename T>
Vector<T>::Vector(T* start, T* end)
{
	std::cout << "Vector(T* start, T* end)" << std::endl;
	check(start != nullptr && end != nullptr);
	m_capacity = m_size = static_cast<int>((end - start));//size_t is enough
	check(m_size > 0);
	m_data = new T[m_size];
	for (int i = 0; i < m_size; i++)
	{
		m_data[i] = *start++;
	}
}
template<typename T>
Vector<T>::Vector(int count, T value)
{
	std::cout << "Vector("<<count<<", "<<typeid(T).name()<<")" << std::endl;
	if (count <= 0)
	{
		throw std::runtime_error("size of vector to init must bigger than zero!");
	}
	m_data = new T[count];
	for (int i = 0; i < count; i++)
	{
		m_data[i] = value;
	}
	m_capacity = m_size = count;
}
template<typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& from)
{
	std::cout << "Vector::operator=Vector<"<<typeid(T).name()<<">" << std::endl;
	if (this == &from)
	{
		return *this;
	}
	//release self data first
	deep_copy_from(from);
	return *this;
}

template<typename T>
Vector<T>::~Vector()
{
	//(2) your code
 
}
template<typename T>
int Vector<T>::size(void) const
{
	return m_size;
}
template<typename T>
bool Vector<T>::empty(void) const
{
	//(3) your code . you have to modify the following code
	return false;
}
template<typename T>
T& Vector<T>::operator[](int n) const
{
	//(4) your code . you have to modify the following code
	static T t;
	n++;//this is wrong!!!!!
	return t;
}
template<typename T>
T& Vector<T>::operator[](int n)
{
	//(4) your code . you have to modify the following code
	static T t;
	n++;//this is wrong!!!!!
	return t;
}
template<typename T>
void Vector<T>::push_back(const T & val)
{
	//(5) your code
	// you have to mind that no space in the first time.
	// you can not create space at constructor!

	m_data[0] = val;//this is wrong!!!!!
}
 
template<typename T>
void Vector<T>::clear(void)
{
	//(6) your code
}
 
template<typename T>
void Vector<T>::deep_copy_from(const Vector<T>& from)
{
	//(7) your code . you have to modify the following code
	this->m_size = from.m_capacity;

}
 
template<typename T>
Vector<T>::Vector(const Vector& from)
{
	//(8) your code . you have to modify the following code
	this->m_size = from.m_capacity;
	 
}
 
template<typename T>
typename Vector<T>::const_iterator Vector<T>::cend() const noexcept
{
    const_iterator itr = const_iterator();
	//(9) your code
 
 
	return itr;
}
 
template<typename T>
typename Vector<T>::const_iterator Vector<T>::cbegin() const noexcept
{
    const_iterator itr = const_iterator();
	//(10) your code
	return itr;
}

 
template<typename T>
void print(const Vector<T>& v, const char* msg)
{
	std::cout << "The contents of " << msg << " are:";
	for (int i = 0; i < v.size(); ++i)
	{
		std::cout << ' ' << v[i];
	}
	std::cout << '\n';
}
template<typename T>
void print_itr(Vector<T>& v, const char* msg)
{
	std::cout << "The contents of " << msg << " are:";
	for (auto itr = v.begin(); itr != v.end(); ++itr)
	{
		std::cout << ' ' << *itr;
	}
	std::cout << '\n';
}
template<typename T>
void print_const_itr(const Vector<T>& v, const char* msg)
{
	std::cout << "The contents of " << msg << " are:";
	for (auto itr = v.cbegin(); itr != v.cend(); ++itr)
	{
		std::cout << ' ' << *itr;
	}
	std::cout << '\n';
}
void test_vector_vector(void)
{
	Vector<Vector<char>> matrix(1, Vector<char>(1, 'c'));
	char str[100] = { 0 };
	int index = 0;
	for (auto& item : matrix)
	{
		for (auto& c : item)
		{
			str[index++] = c;
		}
	}
	check(index == 1);
	for (int j = 0; j < 1; j++)
	{
		assert(str[j] == 'c');
	}
}
 
int main()
{
	Vector<int> a;
 
	Vector<int> first;                   // empty vector of ints
	check(first.size() == 0);
	check(first.empty() == true);
	Vector<int> second(4, 100);                       // four ints with value 100
	check(second.empty() == false);
	check(second.size() == 4);
	check(*second.begin() == 100);
	Vector<int> fourth(second);                       // a copy of third
	check(fourth.size() == second.size());
	check(fourth[0] == 100);
	check(fourth[1] == 100);
	check(fourth[2] == 100);
	check(fourth[3] == 100);
 
	int myints[] = { 16,2,77,29 };
	Vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));
	check(fifth.empty() == false);
	check(fifth[0] == 16);
	check(fifth[3] == 29);
	check(fifth.size() == sizeof(myints) / sizeof(int));
	print(fifth, "fifth");//The contents of fifth are:16 2 77 29 
	fifth.push_back(30);
	check(fifth[4] == 30);
	check(fifth.size() == 5);
	print(fifth, "fifth");//The contents of fifth are:16 2 77 29 30 
	check(fifth.size() == sizeof(myints) / sizeof(int) + 1);
	first = fifth = fifth;
	print(first, "first");//The contents of first are:16 2 77 29 30 
	check(first.empty() == false && first.size() == fifth.size());
	print_itr(fifth, "fifth");//The contents of fifth are:16 2 77 29 30 
	print_const_itr(fifth, "fifth");//The contents of fifth are:16 2 77 29 30 
	std::sort(fifth.begin(), fifth.end());
	{
		Vector<int> t{2, 16, 29, 30, 77};
		check(fifth == t);
	}
	std::cout << "fifith after sort:" << std::endl;
	print_const_itr(fifth, "fifth");//The contents of fifth are:16 2 77 29 30 
	Vector<int> a1(myints, myints + sizeof(myints) / sizeof(int));
	{
		Vector<int> b(a1);
		b.push_back(2);
		check(b[4] == 2);
		auto result = (b == Vector<int>{ 16, 2, 77, 29, 2});
		check(result);
 
		//iterator
		{
			check(b.begin() + b.size() == b.end());
			auto begin = b.begin();
			auto itr = b.begin() + 1;
			check(*begin == 16);
			check(*itr == 2);
		}
		//const iterator
		{
			check(b.cbegin() + b.size() == b.cend());
			auto begin = b.cbegin();
			auto itr = b.cbegin() + 1;
			check(*begin == 16);
			check(*itr == 2);
			check(++begin == itr);
		}
		{
			Vector<long> aa;
			check(aa.begin() == aa.end());
			check(aa.cbegin() == aa.cend());
		}
	}
	{
		Vector<int> b{ 1,3,5,7 };
		b.push_back(9);
	}
	{
		Vector<int> c;
		for (auto i : c){std::cout << i << " ";	}
		c = a1;
		for (auto i : c){	std::cout << i << " ";}
		std::cout << std::endl;
	}
	check(a1.size() == sizeof(myints) / sizeof(int));
	{
		Vector<int> c;
		c = fifth;
		c[0] = 1;
		check(c[0] == 1);
	}
	{
		Vector<int> aa{1, 2, 3};
		Vector<int> b{1, 2, 3, 4};
		check(aa != b);
		auto c = b;
		c.push_back(5);
		check(c != b);
		c = b;
		check(c == b);
	}
	//test char
	{
		Vector<char> arr(10, 'a' );
		char buffer[10] = { 0 };
		int index = 0;
		for (auto& c : arr)
		{
			buffer[index++] = c;
		}
		check(index == 10);
		for (int j = 0; j < 10; j++)
		{
			assert(buffer[j] == arr[j]);
			assert(buffer[j] == 'a');
		}
	}
	test_vector_vector();
	{
		Vector<int> arr1{ 1,1,3 };
		Vector<int> arr2{ 2,2,3 };
		check(arr1 != arr2);
		Vector<int> arr3{ 2,2,3 };
		check(arr2 == arr3);
		Vector<int> arr4{ 2,2,3, 3 };
		check(arr3 != arr4);
		check(arr4 != arr3);
	}
}

预期输出

Vector(void)
Vector(void)
line:494 Pass
line:495 Pass
Vector(4, int)
line:497 Pass
line:498 Pass
line:499 Pass
Vector::deep_copy_from Vector<int>
line:501 Pass
line:502 Pass
line:503 Pass
line:504 Pass
line:505 Pass
Vector(T* start, T* end)
line:287 Pass
line:289 Pass
line:509 Pass
line:510 Pass
line:511 Pass
line:512 Pass
The contents of fifth are: 16 2 77 29
line:515 Pass
line:516 Pass
The contents of fifth are: 16 2 77 29 30
line:518 Pass
Vector::operator=Vector<int>
Vector::operator=Vector<int>
Vector::deep_copy_from Vector<int>
The contents of first are: 16 2 77 29 30
line:521 Pass
The contents of fifth are: 16 2 77 29 30
The contents of fifth are: 16 2 77 29 30
line:527 Pass
fifith after sort:
The contents of fifth are: 2 16 29 30 77
Vector(T* start, T* end)
line:287 Pass
line:289 Pass
Vector::deep_copy_from Vector<int>
line:535 Pass
line:537 Pass
line:541 Pass
line:544 Pass
line:545 Pass
line:549 Pass
line:552 Pass
line:553 Pass
line:554 Pass
Vector(void)
line:558 Pass
line:559 Pass
Vector(void)
Vector::operator=Vector<int>
Vector::deep_copy_from Vector<int>
16 2 77 29
line:573 Pass
Vector(void)
Vector::operator=Vector<int>
Vector::deep_copy_from Vector<int>
line:578 Pass
line:583 Pass
Vector::deep_copy_from Vector<int>
line:586 Pass
Vector::operator=Vector<int>
Vector::deep_copy_from Vector<int>
line:588 Pass
Vector(10, char)
line:599 Pass
Vector(1, char)
Vector(1, class Vector<char>)
Vector(void)
Vector::operator=Vector<char>
Vector::deep_copy_from Vector<char>
line:482 Pass
line:610 Pass
line:612 Pass
line:614 Pass
line:615 Pass
OK good job ! No memory leak.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++程序员Carea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值