前沿:为了跨平台的需要,以及性能考虑,ACE创建了自己的容器。ACE支持两种容器:基于模板的、类型安全的容器,以及基于对象的容器。
基于模板的容器:允许在编译时创建“针对特定类型的容器”;基于对象的容器:支持某一类对象类型的插入和删除。
ACE的容器包含两类:序列容器和关联容器。
序列容器是一种其元素按照线性顺序排列的容器。由于要在容器中进行迭代,各个元素的顺序不会改变。列表、栈、队列、数组和集合都是ACE的一些类所代表的序列的例子。
1、双向链表
双向链表在序列中同时维护有向前和向后的链接,从而可以在序列中进行高效的向前和向后遍历。但不能对元素进行随机访问。
ACE_DLList是ACE提供的双向链表。它是一个基于模板的容器,所以我们需要预先指定我们的列表中使用的元素的类型。
2、双向链表测试代码
(1)双向链表元素定义:DataElement(DataElement.h)
//DataElement元素有一个很好的特性:即它会记住自己现在有多少个实例
//双向链表测试,以下定义的是链表元素类型
class DataElement
{
friend class DataElementEx;
public:
DataElement(){count_++;}
DataElement(int data):data_(data){count_++;}
DataElement(const DataElement& e)
{
data_=e.getData();
count_++;
}
DataElement& operator=(const DataElement& e)
{
data_=e.getData();
return *this;
}
bool operator==(const DataElement& e)
{
return this->data_==e.data_;
}
~DataElement(){count_--;}
int getData(void)const{return data_;}
void setData(int val){data_=val;}
static int numOfActiveObjects(void){return count_;}
private:
int data_;
static int count_;
};
(2)测试类定义:ListTests(ListTests.h)
#pragma once
#include "ace/Containers.h"
#include "DataElement.h"
//双向链表测试
//双向链表支持前向和后向迭代
typedef ACE_DLList<DataElement> MyList;//该容器可以存储元素对象,也可以存储指向对象的指针
class ListTests
{
public:
ListTests(void);
~ListTests(void);
int run(void);
// 显示列表
void displayList(MyList& list);
// 销毁对象
void destoryList(MyList& list);
};
(3)测试类实现(ListTests.cpp)
#define ACE_NTRACE 0
#include "ListTests.h"
int DataElement::count_=0;//必须对静态成员进行初始化
ListTests::ListTests(void)
{
}
ListTests::~ListTests(void)
{
}
int ListTests::run(void)
{
ACE_TRACE (ACE_TEXT("ListTest::run"));
//创建一个列表,插入100个元素
MyList list1;
for(int i=0;i<100;i++)
{
DataElement *element;
ACE_NEW_RETURN(element,DataElement(i),-1);
//注意:存放在容器里面的是指向元素的指针,而不是元素本身
//这意味着,当列表出作用域时候,需要负责删除元素本身,否则数据元素将
//在堆上继续存在,否则会造成内存泄漏
list1.insert_tail(element);
}
//迭代显示列表
this->displayList(list1);
ACE_DEBUG((LM_DEBUG,ACE_TEXT("#of live objects:%d/n"),DataElement::numOfActiveObjects()));
//从调试情况来看,数目为100
//创建list1的一个拷贝
MyList list2;
list2=list1;//此处为浅拷贝
//迭代显示拷贝列表的内容
this->displayList(list2);
ACE_DEBUG((LM_DEBUG,ACE_TEXT("#of live objects:%d/n"),DataElement::numOfActiveObjects()));
//从调试情况来看,对象数目仍然是100
//清除拷贝列表和其所有元素
//因为两个列表有相同的元素,
//这将导致list1包含的指针所指向的数据元素已经被销毁。
this->destoryList(list2);
ACE_DEBUG((LM_DEBUG,ACE_TEXT("#of live objects:%d/n"),DataElement::numOfActiveObjects()));
//从调试情况来看,对象数目为0
//所有列表本身将在此被清理。注:列表析构函数将销毁任何列表拷贝,无论其包含什么数据
//因为在这种情况下,列表包含指向数据元素的指针,此处是销毁这些数据元素的唯一机会。
return 0;
}
// 使用迭代器,显示列表
void ListTests::displayList(MyList& list)
{
ACE_TRACE(ACE_TEXT("ListTest::displayList"));
ACE_DEBUG((LM_DEBUG,ACE_TEXT("Forword iteration/n")));
//前向迭代器
ACE_DLList_Iterator<DataElement> iter(list);
while(!iter.done())
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("%d:"),iter.next()->getData()));
iter++;
}
ACE_DEBUG((LM_DEBUG,ACE_TEXT("/n")));
ACE_DEBUG((LM_DEBUG,ACE_TEXT("Reverse Iteration /n")));
//后向迭代器
ACE_DLList_Reverse_Iterator<DataElement> riter(list);
while(!riter.done())
{
ACE_DEBUG((LM_DEBUG,ACE_TEXT("%d:"),riter.next()->getData()));
riter++;
}
ACE_DEBUG((LM_DEBUG,ACE_TEXT("/n")));
}
// 销毁对象
void ListTests::destoryList(MyList& list)
{
ACE_DLList_Iterator<DataElement> iter(list);
while(!iter.done())
{
delete iter.next();//析构元素,避免内存泄漏
iter++;
}
}
(4)入口函数
// Container_Practice.cpp : 定义控制台应用程序的入口点。
//
#define ACE_NTRACE 0
#include "ace/Containers.h"
#include "ListTests.h"
typedef ACE_DLList<DataElement>MyList;
int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
{
ListTests listtest;
listtest.run();
return 0;
}