您的位置:首页 > 编程语言 > C语言/C++

C/C++程序设计05(泛型编程、容器、STL)

2015-07-17 14:08 211 查看
第九章 STL模板与容器

泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。泛型即是指具有在多种数据类型上皆可操作的含意,与模板有些相似。
标准库模板STL巨大,而且可以扩充,它包含很多计算机基本算法和数据结构,而且将算法与数据结构完全分离,其中算法是泛型的,不与任何特定数据结构或对象类型系在
一起标准模板库是C++的一个新特性,它是基于模板的容器类的库,包括链表、列表、队列以及许多常用的算法,如排序和查找。
STL是一个泛型编程的例子,是由惠普实验室开发的一些列软件的统称。STL被内建在编译器中,STL版本有很多。STL可分为容器(containers)、迭代器(iterators)、空间配置
器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分

1.向量容器vector
必须记住:释放vector对象时,vector包含的元素也一起释放,当容器内有指针或者其他资源分配时特别注意,例子如下:
class Demo
{
public:
Demo() :str_(NULL){}
~Demo()
{
if (str_)
delete[] str_;

}

char* str_;
};

int main()
{
Demo dl;
dl.str_ = new char[32];
strcpy(dl.str_, "asdf ghjk");
vector<Demo>* al = new vector<Demo>();
al->push_back(dl);
delete al;

}

new的vector必须用delete释放,在上列子中,al->push_back(dl),实际上是两个指向同一个地址,delete al语句时,已经删除一遍,当函数结束时候,临时对象dl自动运行
析构函数,再一次删除,由于前面已经删除了,再一次删除就报错。
总结:容器中尽量不要push_back(指针),因为push_back进去是浅拷贝,指向同一个内存,并不是深拷贝,vector<cvMat*>同样也是,曾经遇到过这样的问题。还有一
种解决办法自己定义复制函数(拷贝函数)和赋值操作符。
复制函数和赋值操作符一般是成对出现,虽然类会自动合成复制函数和赋值操作符,但是当数据成员是指针,或者成员表示在构造函数中有分配的其他资源,这时候必须定义复制构造函数(一般成对的也会定义赋值操作符),格式如下使用(上面的解法):

//添加复制构造函数;
Demo(const Demo &cd)
{
this->str_ = new char[strlen(cd.str_) + 1];
strcpy(str_, cd.str_);//这样才是深拷贝;
}


2复制函数和赋值操作符(记住格式)

对含有指针成员变量的类来说,使用默认的拷贝构造和赋值操作是不安全的,具体的原因是默认的函数都属于浅拷贝,所谓浅拷贝就是指只对指针本身进行拷贝操作而对于指针所指向的内容不进行任何操作,这显然至少会带来2个问题,第一个是内存泄漏,因为指针本身被一个新值所覆盖,造成指针原先指向的内存将无法得到释放的机会。另一个问题就是重复引用问题,两个(或者更多)的指针指向同一块内存,当对其中一个指针进行delete操作后,所有对其他指向这块已经被释放的内存的指针的操作,结果都是无法预测的。同样,当修改其中一个对象的指针成员所指向内存中的数据时,其它对象会跟着一起被改变,这显然是错误的。

对于拷贝构造来说,不存在内存泄漏的问题,因为一般对象被创建的时候指针成员都还没有被分配内存,但是存在重复引用的问题。

所以为了避免这些问题,必须显式的定义这两个函数。

对于赋值操作符基本上跟拷贝构造类似,但需要注意以下几点:

1) 防止内存泄漏: 对于指针型成员变量(动态分配内存的)要先释放内存;

2) 对于有基类的情况必须显式的调用基类的的赋值操作,完整例子如下:

class Demo
{
public:
Demo() :str_(NULL){}
~Demo()
{
if (str_)
delete[] str_;

}
//添加复制构造函数;
Demo(const Demo &cd)
{
this->str_ = new char[strlen(cd.str_) + 1];
strcpy(str_, cd.str_);//这样才是深拷贝;
}
//赋值操作符
Demo& operator=(const Demo &cd)
{
a = cd.a;//其他成员的赋值
this->str_ = new char[<span style="color:#ff0000;">strlen(cd.str_) + 1</span>];
strcpy(str_, cd.str_);//这样才是深拷贝;
return *this;//返回对象本身,一定要有星号
}

char* str_;
int a;
};

int main()
{
Demo dl;
dl.str_ = new char[32];
strcpy(dl.str_, "asdf ghjk");
vector<Demo>* al = new vector<Demo>();
al->push_back(dl);
delete al;

}


3.泛型编程

泛型函数(结构体)格式(记住就可以了):

template<typename T>
T fun_Name(T value_in, )
{
T a = ...;
return a;
}

泛型类格式:修改如下即可

template<class T>

定义模板后,具体的类型T,在模板实例化的时候才知道是什么类型.

引申:当函数的参数类型,返回类型等都一样,只是函数名字不一样时,那么可以用函数指针,这样操作类似回调函数一样。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: