C++模板封装Vector和带头结点的双向链表

本文介绍了一个C++模板封装的Vector类和SList类实现细节,重点关注string类型在Vector类拷贝构造和扩容时可能出现的深浅拷贝问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++模板封装Vector:

注意:

在Vector的拷贝构造,扩容函数中,需要注意string的影响。(深层次的深浅拷贝的问题

在插入string类的变量时,这里会发生两个错误,一个是对已经释放的内存进行访问,另一个是内存的多次析构。

我们知道在windows下或者是说在VS2013环境下,string类的大小为28,这是因为string类为了高效的存取数据,类中有一个大小为16的空间,当创建的对象大小小于16时将直接存在对象中,所以在发生内存拷贝时,memcpy并不会出现问题。析构时,新空间和旧空间各自释放各自的空间,并不会发生错误。

但是当对象的大小超过16时,编译器就会创建一块空间存放字符串,并使string中的指针指向这块空间,但是memcpy拷贝时就只拷贝指向空间的指针,这是发生的就是浅拷贝,两个指针指向了同一块内存,在扩容函数中调用delete时已经释放了这块内存,再对其进行访问时,获得的就是随机值,并且在最后析构的时候,因为对已经析构了的内存进行析构,就会导致程序崩溃。


为了解决这个问题:我们可以采用for循环对对象进行深拷贝。(本质是调用string类的 operator=),但是我们不能进行类型的判断而选择不同的代码执行方案(可以选择类型萃取),所以当前选择深拷贝来进行拷贝。

代码:

为了防止分离编译的问题这里将类的声明和定义都放在 Vector.h中。

#pragma once 

#include <iostream>
#include <assert.h>
#include <string.h>
#include <string>

using namespace std;

template<class T>
class Vector
{
public:

	Vector();
	Vector(const Vector<T>& v);
	//Vector<T>& operator=(const Vector<T>& v);
	Vector& operator=(Vector<T> v);
	~Vector();
	

	//inline size_t Size()const;
	inline size_t Size() const;
	inline size_t Capacity() const;
	inline bool Empty();
	void PushBack(const T& x);
	void PopBack();
	void Insert(size_t pos, const T& x);
	void Erase(size_t pos);
	size_t Find(const T& x);
	void Print();
	const T& Back()const
	{
		return *(_finish - 1);
	}
	T& operator[](size_t index)
	{
		return _start[index];
	}
	void Expand(size_t n);
	void Clear()
	{
		_finish = _start;
	}
protected:
	
	T* _start;
	T* _finish;
	T* _endofstorage;
};

//类名  :  aa  vector
//类型名:  aa  vector<T>

template<class T>
Vector<T>::Vector()
:_start(NULL)
, _finish(NULL)
, _endofstorage(NULL)
{}

//v1(v2);
template<class T>
Vector<T>::Vector(const Vector<T>& v)   
{
	_start = new T[v.Size()];
//	memcpy(_start, v._start, sizeof(T)* v.Size());   //string类型数据的拷贝会存在深浅拷贝的问题
	for (int i = 0; i < Size(); ++i)
	{
		_start[i] = v._start[i];
	}

	_finish = _start + v.Size();
	_endofstorage = _start + v.Capacity();
}

template<class T>
Vector<T>& Vector<T>::operator=(Vector<T> v)			//Vector<T>类型   Vector 类名
{
	if (_start != v._start)
	{
		swap(_start, v._start);
		swap(_finish, v._finish);
		swap(_endofstorage, v._endofstorage);
	}
	return *this;
}

template<class T>
Vector<T>::~Vector()
{
	delete []_start;		
	_start = _finish = _endofstorage = NULL;
}

template<class T>
inline size_t Vector<T>::Size()const
{
	return _finish - _start;
}

template<class T>
inline size_t Vector<T>::Capacity() const
{
	return _endofstorage - _start;
}

template<class T>
inline bool Vector<T>::Empty()
{
	return _start == _finish;
}

template<class T>
void Vector<T>::Insert(size_t pos, const T& x)
{
	assert(pos <= Size());

	if (Size() >= Capacity())
	{
		Expand(Capacity() * 2);
	}

	T* end = _finish - 1;
	while (end >= _start + pos)
	{
		*(end + 1) = *end; 
		--end;
	}
	_start[pos] = x;
	++_finish;
}

template<class T>
void Vector<T>::Erase(size_t pos)
{
	assert(pos < Size());

	T* Cur = _start + pos + 1;
	while (Cur != _finish)//<
	{
		*(Cur - 1) = *Cur;
		++Cur;
	}
	--_finish;
}

template <class T>
void Vector<T>::Expand(size_t n)
{
	if (Empty())
	{
		_start = new T[3];
		_finish = _start;
		_endofstorage = _start + 3;
	}
	else if (n > Capacity())	//扩容时进行内存拷贝如果是string类型的时候会出现错误,因为要进行数据拷贝,
								//string有16个字符大小的buf数组空间,小一点的时候是存放在buf中
								//大的时候进行拷贝发生的是浅拷贝,开辟空间,指针指向同一个位置释放空间出错
	{
		size_t size = Size();
		T* tmp = new T[n];
		memcpy(tmp, _start, sizeof(T)* Size());
		//for (size_t i = 0; i < Size(); i++)
		//{
		//	tmp[i] = _start[i];
		//}

		delete []_start;						//调析构函数,再调free, 如果是string深层次调用string的析构函数,
											//浅拷贝导致的析构两次的问题
		_start = tmp;
		_finish = _start + size;
		_endofstorage = _start + n;
	}
}

template <class T>
void Vector<T>::PushBack(const T& x)
{
	Insert(Size(), x);
}

template <class T>
void Vector<T>::PopBack()
{
	Erase(Size() - 1);
}

template <class T>
size_t Vector<T>::Find(const T& x)
{
	T* Cur = _start;
	while (Cur != _finish)
	{
		if (*Cur == x)
		{
			return Cur - _start;
		}
	}
	return -1;
}

template <class T>
void Vector<T>::Print()
{
	T* Cur = _start;
	while (Cur != _finish)
	{
		cout << *Cur << " ";
		++Cur;
	}
	cout << endl;
}



void TestVector()
{
	//Vector<char> v1;
	//v1.PushBack('c');
	//v1.PushBack('c');
	//v1.PushBack('c');
	//v1.PushBack('c');
	//v1.PushBack('c');
	//v1.PushBack('c');
	//v1.PushBack('c');

	//v1.Print();
	//Vector<char>v2(v1);
	//v2.Print();

	Vector<string> v3;  //string类型发生扩容的时候的空间拷贝比较特殊
	v3.PushBack("1");				//char*  []
	v3.PushBack("2");
	//v3.PushBack("111b1111111111111111111111111111111111111111");		
	v3.PushBack("4");
	//v3.PopBack();
	v3.Print();

}

SList.h

#pragma once

#include <iostream>
#include <string>
#include <assert.h>

using namespace std;

template<class T>
struct SListNode{
	SListNode(const T& x)
		: _data(x)
		, _prev(NULL)
		, _next(NULL)
	{}
	T _data;
	SListNode<T>* _prev;
	SListNode<T>* _next;
};

template<class T>
class SList{
	typedef SListNode<T> Node;
public:
	SList()
	{
		_head = new Node(T());
		_head->_prev = _head;
		_head->_next = _head;
	}

	SList(const SList<T>& l);

	//SList<T>& operator=(const SList<T>& l);
	SList<T>& operator=(SList<T> l);

	~SList();
	void PushBack(const T& x);
	void PopBack();
	void PushFront(const T& x);
	void PopFront();
	// pre  newnd  pos
	void Insert(Node* pos, const T& x);
	// pre pos next
	void Erase(Node* pos);
	void Clear();
	void Print();
	void Swap(SList<T>& l);
	size_t Size()const;
	const T& Back()const;
	const T& Front()const;
	bool Empty()const;

protected:
	Node* _head;
};

template<class T>
SList<T>::SList(const SList<T>& l)
:_head(new Node(T()))
{
	_head->_next = _head;
	_head->_prev = _head;

	Node* pCur = l._head->_next;
	while (pCur != l._head)
	{
		PushBack(pCur->_data);
		pCur = pCur->_next;
	}
}

template<class T>
SList<T>& SList<T>::operator=(SList<T> l)
{
	swap(_head, l._head);

	return *this;
}

template<class T>
SList<T>::~SList()
{
	//Node* pCur = _head->_next;
	//Node* Next = NULL;
	//while (pCur != _head)
	//{
	//	Next = pCur->_next;
	//	delete pCur;
	//	pCur = Next;
	//}
	Clear();
	delete _head;
	_head = NULL;
}

template<class T>
void SList<T>::PushBack(const T& x)
{
	Insert(_head, x);
}

template<class T>
void SList<T>::PopBack()
{
	Erase(_head->_prev);
}

template<class T>
void SList<T>::PushFront(const T& x)
{
	Insert(_head->_next, x);
}

template<class T>
void SList<T>::PopFront()
{
	Erase(_head->_next);
}

template<class T>
void SList<T>::Insert(Node* pos, const T& x)
{
	assert(NULL != pos);
	Node* NewNode = new Node(T(x));
	Node* Pre = pos->_prev;

	NewNode->_prev = Pre;
	NewNode->_next = pos;
	Pre->_next = NewNode;
	pos->_prev = NewNode;
}

template<class T>
void SList<T>::Erase(Node* pos)
{
	assert(_head != pos);
	Node* Pre = pos->_prev;
	Node* Next = pos->_next;

	Pre->_next = Next;
	Next->_prev = Pre;
	delete pos;
	pos = NULL;
}

template<class T>
void SList<T>::Clear()
{
	Node* Cur = _head->_next;
	Node* Next = NULL;
	while (Cur != _head)
	{
		Next = Cur->_next;
		delete Cur;
		Cur = Next;
	}
}

template<class T>
void SList<T>::Print()
{
	Node* pCur = _head->_next;

	while (pCur != _head)
	{
		cout << pCur->_data << " ";
		pCur = pCur->_next;
	}
	cout << endl;

}

template<class T>
void SList<T>::Swap(SList<T>& l)
{
	swap(_head, l._head);
}

template<class T>
size_t SList<T>::Size()const
{
	size_t size = 0;
	Node* Cur = _head->_next;
	while (Cur != _head)
	{
		++size;
		Cur = Cur->_next;
	}
	return size;
}

template<class T>
const T& SList<T>::Back()const
{
	return _head->_prev->_data;
}

template<class T>
const T& SList<T>::Front()const
{
	return _head->_next->_data;
}

template<class T>
bool SList<T>::Empty() const
{
	return _head->_next == _head;
}

void TestSList()
{
	SList<string> l1;
	l1.PushBack("1111");
	l1.PushBack("1112");
	l1.PushBack("1113");
	l1.PushBack("1114");
	l1.PushBack("1115");
	l1.Print();
	l1.PopBack();
	l1.Print();
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值