前一段时间看了,现在返回来再看看,还有一些类型前段时间没有来得及看。
描述符类是为了代表数据 允许你安全的访问。Symbian OS 使用描述符来存储还使用字符串
(NUll结尾字符串在C中),还有二进制数据(忘记字符串吧, symbian只有描述符)
主要还是为了节约内存还稳定。String一般使用16位描述符存储(Unicode),二进制一般
使用8位的描述符。descriptor.Format = sprintf()
描述符有12种三类 buffer pointer 和 heap , buffer描述符包含数据在描述符中于
TBuf开头,指针包含一个直向描述符以外的数据buffer的指针于TPtr开头。heap用来
操作堆中的数据HBuf 或者 RBuf;
描述符可是可以修改或者是不可以修改的,由C来标识。默认的描述符长度是16位的,
描述符主要的功能是为了表示字符串。所有可以修改的类继承自TDES,不可以修改的
继承自TDESC,TDES继承自TDESC, TDES 是TDESC加入了可以修改方法的扩展。
size()返回字节长度,length()根据自身长度返回。(数据对其问题)
_LIT比_L好,因为它没有运行时的消耗。_L会在运行时创建TPtrC对象。
TLitC不是从TDEsC继承的。_LIT(KMyString, "My String")-〉const static TLitC<10> KMyString={9, L"My String"}
L("Hello")-〉TPtrC((const TText *) L"Hello")
Tbuf和TBufC用于小的Buffer 想象成数组。
为了空间高效虚方法没有被描述符使用,只是使用了4位来表示描述符类型。
为什么在TbufC中不用存储最大长度呢? 这个是大V的解释:
是说TBufC是模版,定义的时候一般是TBufC<100> test;
100是模版的参数,直接可以作为最大值了,所以TBufC没有iMaxLength这个成员。
而TBuf, TDes有iMaxLength这个成员,虽然TBuf也是一个模版,参数就是最大值,但是TBuf可以通过TDes来修改,而TDes不是模版,所以需要iMaxLength这么一个参数,如果不是TDes这个基类搅合的话,TBuf也可以不用iMaxLength这个成员。
100是模版的参数,直接可以作为最大值了,所以TBufC没有iMaxLength这个成员。
而TBuf, TDes有iMaxLength这个成员,虽然TBuf也是一个模版,参数就是最大值,但是TBuf可以通过TDes来修改,而TDes不是模版,所以需要iMaxLength这么一个参数,如果不是TDes这个基类搅合的话,TBuf也可以不用iMaxLength这个成员。
TBufC使用重载‘=’来实现整体的替换这个里头有模版的参数。
HBuf和RBuf必须自己管理内存.HBufC ->CleanupStack::PopAndDestroy()
RHbuf->(close)->CleanupClosePushL(). CleanupStack::PopAndDestroy();
为什么我们不使用TBufC<100>* myDes = new TBufC<100>;来代替HBufC* myDes=HBufC::New(100);?
就是因为HBufC提供了一些特殊的方法比如ReAllocL();
我们可以使用DES()方法返回TPtr来修改HBufC();
RBuf的使用使用Create方法 不像HBufC使用指针,RBuf看起来就像在栈上使用
内存.
RBuf myBuff;
myBuff.CleanupClosePushL();
myBuff.PopAndDestroy(myBuff);
RBuf可以使用已经分配的空间:
1.
TInt bufferSize=100;
TUint16 buff=
static_cast<TUint16*>(User::AllocL(bufferSize*sizeof(TUint16)));
RBuf myRbuf;
myRbuff.CleanupClosePushL();
myRbuf.Assign(buff,bufferSize);
// ... more code here, can leave on errors
CleanupStack::PopAndDestroy(myRbuf);
2.
HBufC* myHBufC = HBufC::NewL(100);
RBuf myRbuf(myHBufC);
描述符的方法:
不可以修改的:比较compare(),Find(),FindF(),Left(),Right(),
Mid()
可以修改的:Copy(),CopyC(), CopyF(), copyCP(), CopyLC(),CopyUC()
Fill(), FillZ(),Append().AppendFill(),AppendJustify(),AppendNum().
AppendNumFixedWidth(),Format(), AppendFormt(),UpperCase(),LowerCase()
Capitalize(),Delete(),trimLeft(), TrimRight(), TrimAll(),Trim(),PtrZ()=
=ZeroTerminate() + Ptr().
setMax()和setLength() 可以使用在可以修改的描述符中
SetLength()改变当前描述符的长度,Zero()=SetLength(0);
setMax()用来把当前描述符长度设置成最大的长度,这样做的目的是为了在一些场合使
当前的描述符长度正确:
TPtr myDes(externalBuf,buffSize);
myDes.SetMax();
如上面这样的情况,externalBuf是char *, 这样myDes指向这个区域,但是如果没有第二句
那myDes描述符的长度就是0.
把描述符作为数组使用:
使用[]操作符.
在8位和16位描述符的转化:
直接使用Copy 当8位不是UTF-8的时候
否则使用CnvUtfConverter类.utf.h charconv.lib
动态缓冲
CBufBase,CBufSeg,CBufFlat
当不知道最大长度的时候使用动态缓冲 动态缓冲直接使用的并不多,主要被包括
例如熟组API的类使用.
flat buffer 在堆上的连续空间.很少扩充的时候使用 因为扩充的代价很大
segment buffer 不连续 在扩充 插入删除 更有效.缺点不连续访问开销大.
read和write 一般来说动态缓冲使用指针操作,涉及清理栈.
例子:
void DynamicBufferExampleL()
{
TUint8 dataAry1[100];
TUint8 dataAry2[100];
TUint8 outAry[120];
// initialize dataAry1 and dataAry2 with some stuff
TUint8 j=100;
for (TUint8 i=0; i<100; i++)
{
dataAry1[i]=i;
dataAry2[i]= j--;
}
TPtrC8 desAry1(dataAry1,100); // create descriptor for dataAry1
CBufFlat* dynBuf = CBufFlat::NewL(20);
CleanupStack::PushL(dynBuf);
dynBuf->ResizeL(100); // allocate memory to buffer, none to start
dynBuf->Write(0,desAry1); // write desAry1 to
// dynBuf starting at position 0.
dynBuf->Write(3,dataAry2,50); // write first 50 bytes of dataAry2 to
// dynBuf at position 3
dynBuf->Read(0,outAry,50); // reads 50 bytes starting at
// position 0, putting data into buffer
// to outAry
_LIT(KFormat1,"dynbuf pos=%d : %d %d %d %d %d/n");
console->Printf(KFormat1,0,outAry[0],outAry[1],outAry[2],outAry[3],outAry[4]);
dynBuf->ResizeL(120); // add some room to the buffer
dynBuf->Write(90,dataAry1,30);
dynBuf->Read(100,outAry,20);
console->Printf(KFormat1,100,
outAry[0],outAry[1],outAry[2],outAry[3],outAry[4]);
CleanupStack::PopAndDestroy();
}
Output:
dynbuf pos=0 : 0 1 2 100 99
dynbuf pos=100 : 10 11 12 13 14
write不会自动扩充动态缓冲区.
InsertL(), Delete()
InsertL能自动扩充.resizeL(), ExpandL().
Ptr(4)返回第四个位置TPtr8指针,Backptr()(flat和seg不同)
瘦模版类(轻量级模版)
在通用的基类中实现必要的代码逻辑,但是使用类型不安全的TAny*指针而不是一个模版
化类型, 里面的方法是protected的 防止被调用.因为派生类使用模版,所以它可以用于任何的类型,并且类型是安全的.
TFixedArray<type,size>myArray 和一般的数组一样好用,并且提供一些好用的方法 见sdk
描述符数组:在大多少情况下用于字符串数组 例如 listbox.
描述符数组使用动态缓冲存储数据
CPtrC只有Flat的buffer
_LIT(KString1, "My String");
_LIT(KString2, "Test One Two");
TBufC<20> MmDes(KString1);
TBuf<20> MmDes1(KString2);
CDesCArrayFlat myArray = new (ELeave) CDesCArrayFlat(5);
CleanupStack::PushL(myArray); // in case the appends leave
myArray->AppendL(myDes);
myArray->AppendL(myDes1);
/* ... */
CleanupStack::PopAndDestroy(myArray);
使用描述符数组badesca.h 和 bafl.lib (CPTr* or CDesC*)
动态数组:
CArrayFlat<class T>
RArray和RPointerArray更高效 带有R类一般在栈上分配 但是其中内容在堆上
需要调用Close方法.
RArray<TAccount> myAccounts(10,_FOFF(TAccount,iAccountNumber));
iAccountNumber是一个参考值 用于查找 插入 排序.
class TTenant // T class representing a tenant
{
public:
TTenant(const TDesC& aName,TInt aNum)
{iName.Copy(aName),iApartmentNum=aNum;}
TBuf<40> iName;
TInt iApartmentNum;
};
void TestArrayL()
{
/* Define array of tenants, use the apartment number as the array’s key */
RArray<TTenant> renters(10,_FOFF(TTenant,iApartmentNum));
/* Add some tenants to the array, random apartment order */
TTenant renter1(_L("Sue"),520);
TTenant renter2(_L("Bob"),132);
TTenant renter3(_L("Sally"),1004);
User::LeaveIfError(renters.Append(renter1));// if append fails, leave
User::LeaveIfError(renters.Append(renter2));
User::LeaveIfError(renters.Append(renter3));
/* Sort array to be in order of apartment numbers (the key) */
renters.SortUnsigned();
/* Insert new tenant, in apartment number order */
TTenant newRenter(_L("Pippin"),755);
User::LeaveIfError(renters.InsertInUnsignedKeyOrder(newRenter));
/* Print list of tenants, will be in order of apartment now */
_LIT(KFormat1,"Name=%S, Unit=%d/n");
for (TInt i=0;i<renters.Count();i++)
{
console->Printf(KFormat1,
&renters[i].iName,renters[i].iApartmentNum);
}
/* See who is at apartment 520 */
TTenant findT(KNullDesC,520);
TInt index;
index = renters.FindInUnsignedKeyOrder(findT);
if (index != KErrNotFound)
{
_LIT(KFormat2,"Who’s at apartment 520? %S!");
console->Printf(KFormat2,&renters[index].iName);
}
renters.Close(); /* must be done to free the RArray heap memory */
}
Name=Bob, Unit=132
Name=Sue, Unit=520
Name=Pippin, Unit=755
Name=Sally, Unit=1004
Who’s at apartment 520? Sue!
RPointerArray 不能在使用完数组后删除其中的数据.但是key是不支持的. 虽然
不支持int的key但是可是使用TLinerOrder来进行排序 看SDK
其他数据集合类型
双链表 TDblQue<class T>
class CMyObj : public CBase
{
...
TDblQueLink iLink;
...
};
...
/* construct list, supply offset of link member variable
TbdlQue<CMyObj> linkList(_FOFF(CMyObj,iLink));
可以定义一个迭代器TDblQueIter<MyObj> iter(linkList);
A single-linked list is available via the TSglQue<class T>, TSglQue
Link and TSglQueIter<class T> classes.
园型缓冲
CCirBuf<class T> SetLengthL()必须在使用之前调用.
在论坛上找了一下相关的帖子:
http://www.devdiv.net/viewthread.php?tid=17610&highlight=rarray 这个很有价值 还有V兄的comment:
一般来说list, vector等等的实现,如果返回了引用,后面对list, vector进行了修改,之前引用的值都是undefined的。因为list, vector的实现本身是没有要求的(比如使用B树实现的,append以后可能重新排序,那之前的引用很可能会失效)即使绝大多数的实现和你的期望值是一样的,也不能这么用。
不只是symbian有这个问题,stl也是这样的。
不只是symbian有这个问题,stl也是这样的。
RArray可没那么智能, 所以只会简单的做位copy, 不会保存引用这种东东的, 所以一般对C类, 推荐还是使用RPointerArray.
诡异的问题 试验下.
再RArray中存储的类型sizeof >=4 至少4个字节才可以TUnit16 和 TText都不可以。