一個純C++簡陋字符串實現說明,之前是發的原代碼,結果太長。無法讓大家看清。不好意思啊。
其實中的設計很簡單,首先是數據成員設計,只有一個指針。也就是sizeof()它的時候,為4(32位系統下),而STL的string的sizeof()是32。默認情況下,是不會配置內存的,相當于定義了一個空指針。這個指針類型是T *。之所以使用T *,是因為這樣調試的時候,可以看到該字符串內容是什么。如果你定義成void *,那就什么也看不到了。
在XStringBase定義如下:

T * m_Data; /**////<數據指針
一但它有數據后,它就指向字符串描述結構的字符串內容部分。在這個字符串前面,還有8個字節的字符串頭。結構體定義如下
///字符串結構結構體
struct SStringStruct
{
XInt Length; ///<尺寸
XInt Capacity; ///<當前字符串的容量
//Data ///<當前數據指針所在的位置
};
有兩個內容,一個是當前字符串的長度。不含結尾0,一個是當前申請內存的內存大小:容量。
通過下面的函數,取得字符定義的結構體:
SStringStruct * getOriData()
{
return ((SStringStruct *)m_Data) - 1;
}
這樣getOriData()->Length就是字符串的長度了,getOriData()->Capacity就是它的容量了。
///取當前容量
XInt getCapacity() const
{
XInt iRet = 0;
if( isNotNULL(m_Data) )
{
iRet = getOriData()->Capacity;
}
return iRet;
}
///取當前字符串的長度
XInt getLength() const
{
XInt iRet = 0;
if( isNotNULL(m_Data) )
{
iRet = getOriData()->Length;
}
return iRet;
}
這個字符串沒有考慮內存節省的方式而使用COW(改變的時候寫),我個人覺得沒有必要,這樣做會引入線程安全性的問題。我用的每個字符串對象都有一個拷貝。圖省事吧,大多數的時候,不用考慮線程安全性的問題。
為了減少內存碎片,這里內存申請的大都是指定大的倍數。下面是定義:STRING_BLOCK_SIZE = 64;
//字符串內的常量定義,不給外部使用的
enum
{
STRING_BLOCK_SIZE = 64, //單位塊大小
CHAR_SIZE = sizeof(T), //每個字符串的大小
HEAD_SIZE = sizeof(SStringStruct), //字符串頭的字節數
XSTRING_BASE_ENUM_FORCE_DWORD = 0x7FFFFFFF //強制該Enum為32位
}; //字符串最小內存塊大小
在字符的長度增加的時候,會使用ensureCapacity這個函數,確定當前容量是否夠。如果不夠將調用expandCapacity擴展所需要的容量。每次擴展的容量,默認是原來容量的2倍增長。
///確定裝載字符容量(會自動增加0結尾)
void ensureCapacity(XInt paramCharCapacity)
{
if( paramCharCapacity > 0)
{
expandCapacity(paramCharCapacity + 1); //增加一個字符0的位置
}
}
///擴展容量
/**
注意:這個函數,并不會做安全檢查
@param [in] paramMinimumCapacity 指定的最小容量,這個容量是字符個數
*/
template<class T,class Alloctor>
void XStringBase<T,Alloctor>::expandCapacity(XInt paramMinimumCapacity)
ZDH_THROW(XEOutOfMemory)
{
//ZDH_ASSERT(paramMinimumCapacity>0);
XInt iNowCapacity = getCapacity();
if( iNowCapacity < paramMinimumCapacity)
{
XInt iNewCapacity = paramMinimumCapacity * CHAR_SIZE + HEAD_SIZE; //取得實際所需的字節數
iNowCapacity *= 2;
if( iNewCapacity < iNowCapacity) iNewCapacity = iNowCapacity;
XInt iMod = iNewCapacity % STRING_BLOCK_SIZE;
//確保申請的內存為指定大小的倍數
if( iMod > 0 )
{
iNewCapacity += (STRING_BLOCK_SIZE - iMod);
}
SStringStruct * pData = (SStringStruct *)Alloctor::Alloc(iNewCapacity);
//檢查內存是否溢出
if( pData == NULL )
{
throw XEOutOfMemory();
}
//設置基本屬性
pData->Capacity = (iNewCapacity - HEAD_SIZE) / CHAR_SIZE;
pData->Length = getLength();
if( pData->Length > 0 ) //復制數據
{
CopyData( (T *)m_Data, (T *)(pData + 1), getLength() );
}
else
{
*((T *)(pData + 1)) = 0;
}
//釋放原來的
if( m_Data != NULL )
{
Alloctor::Free(getOriData());
}
//開始替換
m_Data = (T *)(pData+1);
}
}
這個字符串我喜歡的地方是它提供了整數轉字符串和字符串轉整數的方法。還提供了類似printf和cat_printf格式字符串的函數。相信寫過C和C++的朋友,應該都喜歡用吧。用它我就不用再像C一樣考慮要給他臨時分配多少空間。另外還提供了查找函數Pos,去除空格函數Trim,大小寫轉換函數uppercase,lowercase,替換ReplaceString,子串SubString等函數。這個字符串還重載了,[]<<等運符串,我們可以這樣定義字符串:
XAnsiString strTemp;
strTemp <<"hello,我是","Rex","我今年",18,"歲";
也可以strTemp.printf("hello %d",18);
總之,就是為了字符串方便簡單易用。
最后,在這里,內存分配使用的是new和delete,不存在移植的問題。