Transferred from: http://dryfish118.spaces.live.com/Blog/cns! Fdcabf8edb1731d0! 660. Entry
Vc6 remember to read the source code of cstring. It is not complicated. It should be from vc7. MFC and ATL share a cstring. The new cstring uses the template technology and other technologies, it is worth mentioning.
First, let's look at the definition of cstring:
Typedef catlstring cstring;
To explicitly use ANSI and Unicode versions, you can use cstringa and cstringw to see their definitions:
Typedef catlstringw cstringw;
Typedef catlstringa cstringa;
The strings of the above three ATL versions are defined:
Typedef cstringt <wchar_t, strtraitatl <wchar_t> catlstringw;
Typedef cstringt <char, strtraitatl <char> catlstringa;
Typedef cstringt <tchar, strtraitatl <tchar> catlstring;
Therefore, cstringt is the true cstring class.
Template <typename basetype, class stringtraits>
Class cstringt:
Public csimplestringt <basetype, _ cstring_impl _: _ mfcdlltraitscheck <basetype, stringtraits >:: c_bismfcdlltraits>
{
};
Cstringt has two template parameters. The first parameter indicates the character type, and the second parameter is known as strtraitatl from the source code:
Template <typename _ basetype = char, class stringiterator = chtraitsos <_ basetype>
Class strtraitatl: Public stringiterator
{
Public:
Static hinstance findstringresourceinstance (_ in uint NID) Throw ()
{
Return (atlfindstringresourceinstance (NID ));
}
Static iatlstringmgr * getdefamanager Manager () Throw ()
{
Return (& g_strmgr );
}
};
From the class declaration, we can see that it provides a string manager, a character iterator, and a function to obtain strings from resources. The string manager is important and will be mentioned later.
Cstringt has no member variables and encapsulates many useful string functions. The data is stored in the base class csimplestringt.
Csimplestringt has only one member variable m_pszdata. Don't underestimate this variable. There are many secrets in it. It is definitely not as simple as his statement:
Pxstr m_pszdata;
Pxstr is Char or wchar_t, but it is encapsulated by the special technology of the template. Csimplestringt does not directly operate m_pszdata, but is obtained through the member function getdata. Let's take a look at this function:
Cstringdata * getdata () const throw ()
{
Return (reinterpret_cast <cstringdata *> (m_pszdata)-1 );
}
This function converts m_pszdata to the memory type of cstringdata, and moves the length of sizeof (cstringdata) forward to a cstringdata object. M_pszdata is the secret here. In fact, each time the memory is allocated, a memory of sizeof (cstringdata) length will be allocated. The first part of the data is formatted as a cstringdata object, then m_pszdata points to the subsequent data, which is the string.
| _______________ | _______________________________________________________ |
Cstringdata m_pszdata
Let's look at the cstringdata statement:
Struct cstringdata
{
Iatlstringmgr * pstringmgr; // string manager for this cstringdata
Int ndatalength; // length of currently used data in xchars (not including terminating null)
Int nalloclength; // length of allocated data in xchars (not including terminating null)
Long nrefs; // reference count: Negative = locked
// Xchar data [nalloclength + 1] // A cstringdata is always followed in memory by the actual array of character data
};
Cstringdata contains all the information about this string, including the string length, memory length, and reference count. In addition, there is a string manager pointer, which is obtained from the template parameter strtraitatl mentioned above. Let's take a look at the Declaration of the iatlstringmgr interface:
_ Interface iatlstringmgr
{
Public:
// Allocate a new cstringdata
Cstringdata * allocate (INT nalloclength, int ncharsize) Throw ();
// Free an existing cstringdata
Void free (cstringdata * pdata) Throw ();
// Change the size of an existing cstringdata
Cstringdata * reallocate (cstringdata * pdata, int nalloclength, int ncharsize) Throw ();
// Get the cstringdata for a nil string
Cstringdata * getnilstring () Throw ();
Iatlstringmgr * clone () Throw ();
};
Iatlstringmgr provides the allocation and destruction of string memory. For more information, see cafxstringmgr.
Let's take a look at how a string is assigned a value first, add a breakpoint to the second line of code below, and the debugging enters:
Cstring S;
S = l "Hello World ";
The copied function is found until the wmemcpy_s function is traced. The following is the stack:
S = l "Hello World ";
Cstringt: Operator = () //
Csimplestringt: Operator = () // B
Setstring (const wchar_t * pszsrc) // C
Setstring (const wchar_t * pszsrc, int nlength) // d
Copychars // E
One row for analysis:
A, the operator that calls the base class csimplestringt =
B. Call setstring.
C. Evaluate the length of the string pszsrc and call the setstring of the two parameters.
D. Call getbuffer to allocate memory space and determine whether the new string overlaps with the existing string. Call copycharsoverlapped to copy the new string without overlap.
E. copychars is wmemcpy_s.
In the preceding step, the getbuffer function is worth noting. Let's proceed to this function to see what happened:
Setstring
Getbuffer //
Preparewrite // B
Preparewrite2 // C
Fork // d
Cafxstringmgr: allocate // E
_ Malloc_dbg // F
A. Call preparewrite.
B. Determine whether the reference count is greater than 1 or the length is insufficient. If any of the conditions is met, you must call preparewrite to re-allocate the memory. Otherwise, m_pszdata is directly returned.
C. First, determine whether the length of the new application is smaller than the Memory Length. If it is smaller than the Memory Length, set the length to the existing Memory Length. Then, determine whether the reference count is greater than 1. If yes, call fork to apply for memory again. If the reference count is not greater than 1, check whether you need to apply for memory. If yes, re-allocate. There is a simple principle of reallocation, which is clear in the following section:
If (polddata-> nalloclength <nlength)
{
// Grow exponentially, until we hit 1 K.
Int nnewlength = polddata-> nalloclength;
If (nnewlength> 1024)
{
Nnewlength ++ = 1024;
}
Else
{
Nnewlength * = 2;
}
If (nnewlength <nlength)
{
Nnewlength = nlength;
}
Reallocate (nnewlength );
}
D. Extract the old cstringdata, clone an iatlstringmgr instance, and allocate nlength memory. Format the newly allocated memory and release the old memory. Note that the release method does not directly free the memory, but calls the release of cstringdata:
Void release () Throw ()
{
Atlassert (nrefs! = 0 );
If (_ atlinterlockeddecrement (& nrefs) <= 0)
{
Pstringmgr-> free (this );
}
}
We can see that the memory is free only when the reference count is less than or equal to 0.
E. For details, refer to the Code:
Cstringdata * cafxstringmgr: allocate (INT nchars, int ncharsize) Throw ()
{
Size_t ntotalsize;
Cstringdata * pdata;
Size_t ndatabytes;
Ndatabytes = (nchars + 1) * ncharsize;
Ntotalsize = sizeof (cstringdata) + ndatabytes;
Pdata = (cstringdata *) malloc (ntotalsize );
If (pdata = NULL)
Return NULL;
Pdata-> pstringmgr = this;
Pdata-> nrefs = 1;
Pdata-> nalloclength = nchars;
Pdata-> ndatalength = 0;
Return pdata;
}
We can see that the actually allocated memory size is the string length + 1 null + sizeof (cstringdata)
F. allocate memory.