C++顺序表模板练习 以及 剖析易出现的浅拷贝问题

/* C++顺序表模板练习 以及 剖析易出现的浅拷贝问题 */

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

#include <string>

using namespace std;

template <typename T>

class SeqList

{

public:

SeqList();

SeqList(const SeqList& s);

~SeqList();

void PushBack(const T& d);

void PopBack();

void PushFront(const T& d);

void PopFront();

int Find(const T& d);

void Reverse();

void Insert(int pos, const T& d);

void sort();

SeqList& operator=(const SeqList& s);

void Print()

{

int i = 0;

for(i = 0; i < _size; i++)

{

cout<<_data[i]<<"  ";

}

cout<<endl;

}

private:

void _check_capacity()

{

if(_size == _capacity)

{

T* tmp = new T[2 * _capacity + 3];

//======注意 1 memcpy()浅拷贝问题 ===================

//对于含有指向动态开辟空间的类

//memcpy() 会出现浅拷贝现象 导致两个类的成员指针

//指向同一块空间 析构两次时导致【程序崩溃】

//比如 string类 内部含有这样一个指针

//当然 还有初始预留的空间 如果字符串没有超过预留空间

//指向动态空间的指针为空 用memcpy()也没事

//但当这个指针指向空间是 一等会由于浅拷贝导致析构

//失败的

//==============================================

string类 结构示意图

// memcpy(tmp, _data, _size * sizeof(T));

//===========================================

//解决方法

//利用 string类 自带的operator=()一个一个复制

//避免出现浅拷贝现象

//不过memcpy()也有优点 那就是效率高

//===========================================

for(int i = 0; i < _size; i++)

{

tmp[i] = _data[i];

}

delete[] _data;

_data = tmp;

_capacity = 2 * _capacity + 3;

}

}

private:

int _size;

int _capacity;

T* _data;

};

//=================注意2 默认拷贝函数出现浅拷贝问题 ===========

//这要写 拷贝构造 防止出现浅拷贝问题

// 例如对于string这种含有指向动态开辟空间 的 指针成员

template <typename T>

SeqList<T>::SeqList(const SeqList<T>& s)

{

_data = new T[s._size];

int i = 0;

for(i = 0; i < s._size; i++)

{

_data[i] = _data[i];

}

_size = s._size;

_capacity = _size;

}

template <typename T>

SeqList<T>::SeqList()

:_size(0)

,_capacity(3)

,_data(new T[_capacity])//注意:声明类变量时要先声明_capacity 再生命_data

{

//cout<<typeid(_capacity).name() <<endl;

//cout<<"SeqList()"<<endl;

}

template <typename T>

SeqList<T>::~SeqList()

{

if (_data != NULL)

{

delete[] _data;

_data = NULL;

}

}

template <typename T>

void SeqList<T>::PushBack(const T& d)

{

_check_capacity();

_data[_size] = d;

_size++;

}

template <typename T>

void SeqList<T>::PopBack()

{

if(_size > 0)

{

_size--;

}

}

template <typename T>

void SeqList<T>::PushFront(const T& d)

{

_check_capacity();

int i = _size;

while(i)

{

_data[i] = _data[i - 1];

i--;

}

_data[0] = d;

_size++;

}

template <typename T>

void SeqList<T>::PopFront()

{

int i = 0;

for(i = 0; i < _size - 1; i++)

{

_data[i] = _data[i + 1];

}

_size--;

}

template <typename T>

SeqList<T>& SeqList<T>::operator=(const SeqList& s)//注意用SeqList<T>&

{

if(this != &s)

{

delete[] _data;

_data = new T[s._capacity];

memcpy(_data, s._data, s._size * sizeof(T));

_size = s._size;

_capacity = s._capacity;

}

return *this;

}

template <typename T>

int SeqList<T>::Find(const T& d)

{

int i = 0;

for (i = 0; i < _size; i++)

{

if(_data[i] == d)

{

return i;

}

}

return -1;

}

template <typename T>

void SeqList<T>::Reverse()

{

int left = 0;

int right = _size - 1;

while(left < right)

{

swap(_data[left], _data[right]);

left++;

right--;

}

}

template <typename T>

void SeqList<T>::Insert(int pos, const T& d)

{

if(pos < 0 || pos > _size)

{

return;

}

_check_capacity();

int i = _size;

_size++;

while(i > pos)

{

_data[i] = _data[i - 1];

i--;

}

_data[pos] = d;

}

template <typename T>

void SeqList<T>::sort()

{

int i = 0;

for(i = 0; i < _size; i++)

{

bool flag = true;

for(int j = 0; j < _size - i - 1; j++)

{

if(_data[j] > _data[j + 1])

{

T temp = _data[j];

_data[j] = _data[j + 1];

_data[j + 1] = temp;

flag = false;

}

}

if(flag)

{

return;

}

}

}

int main()

{

{

//SeqList<int> s1;

/*s1.PushBack(1);

s1.PushBack(2);

s1.PushBack(3);

s1.PushBack(4);

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();*/

//s1.PushFront(1);

//s1.PushFront(2);

//s1.PushFront(3);

//s1.PushFront(4);

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

/*SeqList<string> s2;

s2.PushBack("1");

s2.PushBack("11111112222222222");

s2.Print();*/

//s2.PushBack();

//s2.PushBack();

//s2.PushBack();

SeqList <string> s1;

s1.PushBack("11111");

s1.PushBack("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");

s1.PushBack("33333");

s1.PushBack("44444");

s1.PushBack("44444");

/*s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");*/

s1.Print();

SeqList <string> s2(s1);

//s2 = s1;

s2.Print();

/*s1.PushBack(4);

s1.PushBack(3);

s1.PushBack(2);

s1.PushBack(1);

s1.Print();*/

/*s1.sort();

s1.Print();

cout<<s1.Find(3)<<endl;

s1.Insert(s1.Find(3),4);

s1.Print();*/

/*SeqList<int> s2 = s1;

s2.Print();*/

}

//test2();

getchar();

return 0;

}

时间: 2024-10-14 10:34:18

C++顺序表模板练习 以及 剖析易出现的浅拷贝问题的相关文章

线性表顺序表模板 纯本人手工创造

/* ***********************************************Author        :mubaixuCreated Time  :2015-12-08 20:45:05File Name     :线性表顺序存储操作************************************************ */ 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <mal

链表模板、队列模板、顺序表模板、栈模板、

//利用容器适配器实现栈和队列 #pragma once #include<iostream> #include<string> #include<cassert> using namespace std; template<typename T> struct Node { public: Node(const T& d) :_next(NULL) , _prev(NULL)     ,_data(d){} T _data; Node<T&g

C++ 数据结构学习一(顺序表)

//sequentiallist.h 顺序表模板类 #ifndef SEQUENTIAL_LIST_HXX#define SEQUENTIAL_LIST_HXX using std::cout; using std::endl; const int MaxSize=100; //顺序表数组最大值 template<class T>class SeqList //定义模板类SeqList(顺序表){ public: SeqList() { length=0; } //无参构造函数,建立一个空的顺

函数模板在c++动态顺序表中的大作用

函数模板提供了一种机制通过它我们可以保留函数定义和函数调用的语义在一个程序位置上封装了一段代码确保在函数调用之前实参只被计算一次. 函数模板提供一个种用来自动生成各种类型函数实例的算法程序员对于函数接口参数和返回类型中的全部或者部分类型进行参数化(parameterize)而函数体保持不变. 函数模板使用注意事项: 1.每个函数模板前边都需要添加模板声明例如:template<typename T> 2.在模板类的使用时,注意其类型改变,例如: template<typename T&g

模板实现顺序表

类模板的成员函数: 类模板的成员函数本身是一个普通函数.但是,类模板的每个实例都有其自己版本的成员函数.因此,类模板的成员函数具有和模板相同的模板参数.因此,在=定义在类模板之外的成员函数就必须以template开始,后跟类模板参数列表. 类模板中的友元函数: 类模板中的友元函数,应该在类中定义.若只在类中声明,在类外定义,则在链接时会出现错误. 类模板实现顺序表: "SeqList.h" //冒泡法 "test.cpp"

C++模板实现动态顺序表(更深层次的深浅拷贝)与基于顺序表的简单栈的实现

前面介绍的模板有关知识大部分都是用顺序表来举例的,现在我们就专门用模板来实现顺序表,其中的很多操作都和之前没有多大区别,只是有几个比较重要的知识点需要做专门的详解. 1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include<stdlib.h> 5 using namespace std; 6 7 template <class T> 8 class Vector 9 { 10 publ

用模板实现顺序表与单链表

//顺序表 #include<iostream> using namespace std; template<typename T> class SeqList { public: SeqList(); ~SeqList(); SeqList(const SeqList& s); SeqList& operator=(const SeqList &s); void _CheakCapacity(); void PushBack(const T& x)

动态顺序表 与 双向链表的模板类

//////////////////////////////////////////////////////////////////////// /////////////////////泛型编程之动态顺序表的模板///////////////////////// //////////////////////////////////////////////////////////////////////// #include<iostream> #include<string> u

C++的标准模板库STL中实现的数据结构之顺序表vector的分析与使用

摘要 本文主要借助对C++的标准模板库STL中实现的数据结构的学习和使用来加深对数据结构的理解.即联系数据结构的理论分析和详细的应用实现(STL),本文是系列总结的第一篇,主要针对线性表中的顺序表(动态数组)STL vector进行分析和总结. 引言 因为前段时间对台大的机器学习基石和技法课程进行了学习,发如今详细的实现中经常涉及到各种类型的数据结构,比方线性表.二叉树.图等,在使用这些数据结构时感到有些吃力.主要是对一些主要的数据结构理解的不够.所以趁着暑假假期.近期一段时间总会抽出时间复习一