Symbian点滴3对象的创建和释放以及对象的二阶段构造

虽然Symbian使用的是c++语言,但是由于手机系统的硬件限制,与c++语言差别还是比较大,Symbian定义了一套自己的东西。

主要是对象的二阶段构造,清除栈。

1.堆和栈。

堆资源比较大,可以动态分配内存空间,在堆上创建的对象,使用以后都要显式的清除。

一般使用new来在进程的默认堆上分配一个空间。如果内存不足就会报一个异常。一个小列子

//CMyClass类定义

class CMyClass : public CBase

{

public:

CMyClass();//构造函数

~CmyClass();//析构函数

void Function();//普通函数

}

//在堆上创建cmyclass类的对象

CMyClass* ptr = new CMyClass;

if(ptr != null)

{

 ptr->Function();//调用方法

delete ptr;//释放指针指向的内存空间

ptr =null;//设置指针为null

在上面代码中,创建类的对象的时候有可能因为内存不足而报错,所以要先检查ptr是不是null,然后才可以调用function 方法。

Symbian中提供了一个ELeave宏,并且重载了new操作符。使用new(ELevae)创建对象的时候,如果内存分配失败,创建的函数将不再执行后面的代码,而是立即退出。所以使用new(ELeave)创建对象,可以省略检查对象是不是为null的步骤

CMyClass* ptr = new CMyClass;

 ptr->Function();//调用方法

delete ptr;//释放指针指向的内存空间

ptr =null;//设置指针为null

-----------------------------------------------------------

在说说栈(stack)。栈上的对象也称为自动变量,因为他不用手工去创建和释放空间。只是栈的空间很小,Symbian系统的栈只有8kb。所以只用来创建简单的字段或者对象。

2.清除栈(CleanUp Stack)

  清除栈的作用就是保证在异常发生的时候释放堆上的对象。

还使用上面的列子,看一个函数方法

void SomeClass::FunctionL()

{

  TInt integer;

  CMyClass* object = new(ELeave)CMyClass;

object->Function();

delete object;

object =null;

}

 CMyClass* object = new(ELeave)CMyClass;如果这个步骤没有成功,异常的话,integer和object都会释放内存资源的,不会发生内存泄漏的问题。

但是如果生成类的步骤成功,但是在执行Function()的时候错误,发生异常了。这个Function()方法会立刻返回,integer和object会被自动释放,但是object指向的CMyClass对象失去了唯一可以访问他的指针,这个对象的空间成为系统的内存漏洞。

  避免这个情况的方法就是使用清除栈。CleanupStack。原来就是将可能异常退出的对象,在他执行之前将对象的指针压入这个清除栈。使用CleanupStack::PushL()函数。

void SomeClass::FunctionL()

{

  TInt integer;

  CMyClass* object = new(ELeave)CMyClass;

//后面的代码可能有一场,会丢失object,造成object执行的cmyclass不可访问,所以先把他压入栈

CleanupStack:PushL(object);

object->Function();

//程序没有异常,将object对象弹出清除栈

Cleanup::Pop();//弹出栈但是没有清除资源

delete object;

object =null;

}

(CleanupStack主要3个方法PushL,Pop,PopAndDestroy//弹出并清除了资源)

3类对象的两阶段构造

Symbian提供的两阶段构造方法,配合清除栈,保证异常退出时候系统不会产生内存泄漏。

3。1原理。

c++中new方法完成两个功能:一个是在堆上申请空间,然后就是执行构造函数完成对对象的构造。

所以在Symbian中的重要规则就是:

第一阶段使用new(Eleave)申请对象空间。并且调用该类的默认构造函数,而且这个构造函数必须是没有异常发生的

第二阶段讲对象压入清除栈,只有调用类的ConstructL()方法,进行一些可能发生异常的操作

所以一个标准的C类应这样定义:

class CClass1 : CBase

{

public:

CClass1();

~CClass1();

void ConstructL();//新增这个函数,里面执行可能有异常发生的操作

private:

CClass1* member;

}

CClass1::CClass1()//构造函数执行肯定不会有异常发生的操作

{

}

CClass1::ConstrunctL()//执行可能会有异常发生的操作

{

   member = new(ELeave)CClass1;

}

CClass1::~CClass1()

{

  delete member;

}

这样,调用这个类的时候,可以这样写。就是两个阶段的构造

CClass1* obj = new(ELeve)CClass1;

CleanupStack::PushL(obj);

obj->ConstructL();

...

CleanupStack::PopAndDestroy();

-----------------------------------------------------------------------

但是这样写有点麻烦。就是生成类的对象的时候,每次都要写4行代码。所以要进一步封装

Symbian的规范是使用静态的newL()和newLC()。然后吧构造函数报刊constructL都变成私有的函数。这样写:

class CClass1 : CBase

{

public:

static CClass1* newL();

static CClass1* newLC();

~CClass1();

private:

CClass1();

void ConstructL();//新增这个函数,里面执行可能有异常发生的操作

private:

CClass1* member;

}

CClass1* CClass1::NewLC()//没有执行出栈操作。所以调用newLC以后,要调用一下出栈函数

{

CClass1* self = new(ELeave)CClass1;

CleanupStack::PushL();

self->ConstructL();

return self;

}

CClass* CClass::NewL()//newl方法调用newLC方法,包含了出栈操作。

{

 CClass1* self = CClass1::NewLC();

 CleanupStack::Pop();

 return self;

}

本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

原文地址:https://www.cnblogs.com/zjypp/p/2319399.html