CBase类的内幕 - 六个本质问题(英文)

原创 2007年09月20日 15:33:00
 非常好的文章,建议所有symbian程序员仔细阅读!
不知道有没有志愿者可以为大家翻译成中文啊?

Inside CBase class - Six Essential Questions
Tutorial posted August 1st, 2007 by rensijie in
Basics
Platforms:
Symbian OS
Keywords:
CBase

Everybody knows C-class in Symbian, the so called C-class is the one derived from class CBase. CBase is widely used in Symbian APIs, because it represents the class which should be created on heap. Every Symbian programmer knows how to call NewL() or NewLC() ( may be new (ELeave) ) of the CBase derived class to create the object, but not many people would really look into the CBase class itself to see why it has some interesting features.

If you can answer the following questions, you can skip this article, because you are a Symbian programmer with strong curiosity. If you are not sure about some answers, I recommend you to read this ariticle, because CBase class is essential in Symbian OS and it's interesting to know some features of this class. The questions are:

Why does cleanup stack has 3 versions of PushL() including PushL( CBase *aPtr )?
Why does CBase have a public virtual destructor?
How is CBase derived object initialized to binary zeroes?
Why is CBase derived object initialized to binary zeroes?
Why use new[] to initialize CBase derived object is not recommended?
Why does CBase has a private copy constructor and a private operator = function?
Let's get into these questions one by one.


Why does cleanup stack has 3 versions of PushL() including PushL(CBase *aPtr)?

It's an interesting question, there're 3 versions of PushL() in CleanupStack, they're PushL(TAny *aPtr), PushL(CBase *aPtr) and PushL(TCleanupItem anItem), why not just PushL(TAny *aPtr) and PushL(TCleanupItem anItem)? Let's see how cleanup stack works. Usually we use the code like this:
JAVA手机网[www.cnjm.net]


JAVA手机网[www.cnjm.net]
CTest* test = CTest::NewL();        // CTest is a CBase derived class
CleanupStack::PushL( test );
test->FunL();
CleanupStack::PopAndDestroy();

It's the regular use of cleanup stack, push the pointer "test" into the cleanup stack because FunL() may leave, after that, if everything is fine, pop the pointer and destory the object. Let's consider how does cleanup stack destory the object when calling PopAndDestroy(), according to the SDK helper,
"If the item on the stack is a CBase* pointer, the pointer is removed from the stack and the object is destroyed with delete. If the item on the stack is a TAny* pointer, the pointer is removed from the stack and the memory occupied by the object is freed with User::Free()."

Why does cleanup stack has to judge if the pointer's type is CBase* or TAny*? Becasue a class may provide a private destructor! If a class has a private destructor, calling delete on this pointer will be invalid. In this case, system only calls User::Free() to free the memory of the object itself but can't invoke its destructor.

JAVA手机网[www.cnjm.net]
What happens to CBase derived class? If you take a look at e32base.h(the declaration of CBase is inside, actually part of the declaration), you will find CBase has a public virtual destructor. This ensures the cleanup stack can call delete on the CBase and its derived classes' pointers. It's useful to keep this in mind that if you push a non-CBase class pointer into the cleanup stack, the stack won't call your class's destructor. So, in most of the cases, you would like to either push CBase derived class into cleanup stack or never allocate heap memory in other types of classes.

But if you really want to allocate heap memory in other types of classes, the third version of PushL() can help you out. What you need to do is define a function which will do the cleanup and wrap the object by TCleanupItem.


Why does CBase have a public virtual destructor?

We can divide this question into 2 parts, why virtual, why public? The answer above tells you why public. The reason to make it virtual is simple. Sometimes you want to write the code like this:
JAVA手机网[www.cnjm.net]

JAVA手机网[www.cnjm.net]

CBase* test = CTest::NewL();        // CTest is a CBase derived class
CleanupStack::PushL( test );
test->FunL();
CleanupStack::PopAndDestroy();

With the virtual keyword, cleanup stack can make sure it will destroy the object properly by the base class's pointer.


How is CBase derived object initialized to binary zeroes?

Luckily, since all the new operator functions of CBase is inline, we can see the implementation of every function in e32base.inl. For example for "TAny* operator new(TUint aSize, TLeave)" the implementation is :


inline TAny* CBase::operator new(TUint aSize, TLeave)
       { return User::AllocZL(aSize); }

Here it uses User::AllocZL(), it allocates a cell of specified size from the current thread's default heap, clears it to binary zeroes, and leaves if there is insufficient memory in the heap. That's how CBase derived object is initialized to binary zeroes?


Why is CBase derived object initialized to binary zeroes?

Let's consider the code below :


CTest* CTest::NewLC()
JAVA手机网[www.cnjm.net]
{
       CTest* self = new ( ELeave ) CTest;
       CleanupStack::PushL( self );
       self->ConstructL()
       return self;
}

void CTest::ConstructL()
{
       iPointer = CMustLeave::NewL();        // assume this leaves
}

CTest::~CTest()
{
       if( iPointer )
       {
               delete iPointer;
               iPointer = NULL;
       }
}

If CBase doesn't initialize the object to binary zero, and you don't initialize the iPointer to NULL manually, the initial value of iPointer is uncertain. Once CMustLeave::NewL() leaves, the value of iPointer is still uncertain(in most of the cases it's not zero). Since in NewLC, CTest was pushed into the cleanup stack, so system will pop the pointer and call CTest's destructor. This will cause the problem, because the if condition will be true and you will call delete on a pointer which doesn't pointer to a legal memory. Mostly program will crash. You will not meet this problem if iPointer was initialized to zero(NULL).


Why use new[] to initialize CBase derived object is not recommended?
JAVA手机网[www.cnjm.net]

There're a number of overloaded new operator functions in CBase class, but there's no new[] operator function. So if you use new[] to create CBase objects, you will not get the memory with binary zero. If you want to create a array of CBase derived class you can use the class like RPointerArray to deal with it.


Why does CBase has a private copy constructor and a private operator = function?

This is a general method to prevent the developer from the shallow copy accidently. If you write the code like this :


CBase* pointer = new ( ELeave ) CBase;
CBase base = *pointer;                // call copy constructor

The compiler will complain "illegal access from CBase to protected/private member CBase::CBase(const CBase&)", because the second line will try to call the copy constructor of CBase. If you write the code like :


CBase* pointer = new ( ELeave ) CBase;
CBase base;
base = *pointer;                // call operator =

The compiler will also complain because it will call the operator = function. If you really want to do the deep copy you can write your own public copy constructor and operator = function. The reason that CBase do this is in most cases you will allocate some heap memory inside a CBase derived class, and it doesn't make sense(or I can say it's dangerous)to use the default copy constructor or default operator = function of this kind of class. So CBase turns this feature off by default.

Actually, in Symbian, to provide your own public version of copy contructor or operator = function is not a good idea neither. Because these 2 function are not leaving functions, but the code inside these 2 functions may leave sometimes( will call new (ELeave) or NewL() ). That's a paradox. The good manner is to provide a leaving function named, let's say, CloneL() to do the copy task.

从问题看本质: 研究TCP close_wait的内幕

(原文地址:http://ahuaxuan.iteye.com/blog/657511) 最近遇到的一个关于socket.close的问题,在某个应用服务器出现的状况(执行netstat -np |...

从问题看本质: 研究TCP close_wait的内幕

最近遇到的一个关于socket.close的问题,在某个应用服务器出现的状况(执行netstat -np | grep tcp):  tcp        0      0 10.224.122...

从问题看本质: 研究TCP close_wait的内幕

/* * @author: ahuaxuan * @date: 2010-4-30 */ 最近遇到的一个关于socket.close的问题,在某个应用服务器出现的状况(执行netstat ...

六个国外免费DNS服务-做英文与外贸网站必备工具

DNS 是计算机域名系统 (Domain Name System 或Domain Name Service) 的缩写,它是由解析器以及域名服务器组成的。这里说的DNS解析服务是互联网绝大多数应用的实际...

网站改版需要注意的六个问题

  • 2012年07月20日 21:48
  • 32KB
  • 下载

英文网站不可缺少的六个页面包括

网页设计   英文网站不可缺少的六个页面包括:首页、关于我们、FAQ、隐私保护、条款声明、联系我们。SEO优化博客Charles认为隐私保护及条款声明是英文网站建设特别重视的,应该多加注意。   ...
  • allenlf
  • allenlf
  • 2011年10月31日 11:57
  • 288

java初学者必须知道的六个问题!【经典】

对于这个系列里的问题,每个学Java的人都应该搞懂。当然,如果只是学Java玩玩就无所谓了。如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列。内容均来自于CSDN的经典老贴。...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:CBase类的内幕 - 六个本质问题(英文)
举报原因:
原因补充:

(最多只允许输入30个字)