About CString Summary (2006-9-16-18:43) Summary of CString
Serial operation is one of the most common and basic operations in programming. As a VC programmer, both rookie and master have used CString. And it seems like it's hard to get away with it (although it's not a library in standard C + +). Because this class provided in MFC is very convenient for us to manipulate strings, CString not only provides a variety of rich operation functions, Operator overloading, which allows us to use the string more intuitively than basic, and it also provides dynamic memory allocation, which reduces the risk of many string arrays being out of bounds. However, we also experience in the use of CString is simply too easy to make mistakes, and some elusive. So there are many high man standing over, suggest to abandon it.
In this, I personally think: CString package is really perfect, it has many advantages, such as "easy to use, powerful, dynamic allocation of memory, a large number of copies of it can save memory resources and high efficiency, fully compatible with standard C, while supporting multibyte and wide bytes, because of the exception mechanism so use IT security side Then "In fact, the use of the process is easy to make mistakes, it is because we do not know enough about it, especially its implementation mechanism." Because most of us do not love to read about it so deeply at work, not to mention it is in English.
Because the other day I encountered a problem that was not a problem but was particularly difficult to solve and inexplicable. Finally found is due to CString, later, no way, I put the whole CString of the realization of all read over again, just panic dawu, and thoroughly understand the cause of the problem (this problem, I have on the csdn on the post). Here, I would like to sum up some of my knowledge about CString, for his (her) people to learn from, perhaps there is my understanding of the mistake, hope that the discovery can inform me, I am grateful.
1 CString implementation of the mechanism.
CString is the "reference" to manage the string, "reference" the word I believe that we are not unfamiliar, like window kernel objects, COM objects, etc. are implemented by reference. CString is also a mechanism to manage allocated chunks of memory. In fact, the CString object has only one pointer member variable, so the length of any CString instance is only 4 bytes.
That is: int len = sizeof (CString);//len equals 4.
This pointer points to an associated reference memory block, as shown in figure: CString str ("ABCD");
___
____________ | |
| | | |
| 0x04040404 | | | Head, for reference memory block related information
|____________| | |
STR |___|
|' A ' | 0x40404040
|' B ' |
|' C ' |
|' d ' |
| 0 |
Because of this, one such block of memory can be referenced by multiple CString, such as the following code:
CString Str ("ABCD");
CString a = str;
CString b (str);
CString C;
c = b;
The result of the above code is that the member variable pointer in the top four objects (STR,A,B,C) has the same value and is 0x40404040. And how many of these chunks of memory do you know about the CString reference it? Also, it records some information. such as the number of references, string length, allocated memory length.
The structure of this reference memory block is defined as follows:
struct CStringData
{
Long nrefs; Indicates how many CString reference it. 4
int ndatalength; The actual length of the string. 4
int nalloclength; Total allocated memory length (excluding 12 bytes of this header). 4
};
With this information, CString can correctly allocate, manage, and release reference memory blocks.
If you want to get this information when you debug the program. You can type the following expression in the Watch window:
(cstringdata*) ((cstringdata*) (This->m_pchdata)-1) or
(cstringdata*) ((cstringdata*) (Str.m_pchdata)-1)//str refers to CString instance
Because of this good mechanism, CString is not only efficient but also less allocated in a large number of copies.
Continued
2 LPCTSTR and GetBuffer (int nminbuflength)
These two functions provide a compatible conversion to standard C. In practice, the frequency is very high, but it is the most error-prone place. These two functions actually return pointers, but what's the difference? And what happens behind the scenes when you call them.
(1) lpctstr its execution process is very simple, but simply returns the string address of the reference memory block. It is provided as an operator overload,
So sometimes implicit conversions can be used in code, but sometimes forced conversion is required. Such as:
CString str;
Const char* p = (LPCTSTR) str;
Suppose you have such a function, Test (const char* p); You can call it this way.
Test (str);//This will be implicitly converted to LPCTSTR
(2) getbuffer (int nminbuflength) It is similar and will return a pointer, but it is somewhat different and returns the LPTSTR
(3) What is the difference between the two? I would like to tell you that it is fundamentally different, generally speaking LPCTSTR conversion should only be used when the constant, or to do the function of the entry; GetBuffer (...) After you remove the pointer, you can use this pointer to modify the contents, or to do the function's entry. Why, then? There may be a lot of code like this:
CString Str ("ABCD");
char* p = (char*) (const char*) str;
P[2] = ' Z ';
In fact, there may be such a code, your program is not wrong, and the program also run very well. But it is very dangerous. Look again
CString Str ("ABCD");
CString test = str;
....
char* p = (char*) (const char*) str;
P[2] = ' Z ';
strcpy (P, "akfjaksjfakfakfakj");/This is a dead end.
Do you know what the value in test is now? The answer is "ABZD". It's also changed, and that's not what you expected. But why is that so? If you think about it, you'll understand, as I said before, because CString points to a reference block, str and test point to the same place, and when you p[2]= ' Z ', of course, test changes as well. So use it as a LPCTSTR to do the conversion, you can only read this piece of data, never to change its content.
What if I want to modify the data directly through the pointer? is to use GetBuffer (...). Look at the following code:
CString Str ("ABCD");
CString test = str;
....
char* p = str. GetBuffer (20);
P[2] = ' Z '; Execution to this, now the value in test is still "ABCD"
strcpy (P, "akfjaksjfakfakfakj"); Execution to this, now the value in test is still "ABCD"
Why is this. In fact, when GetBuffer (20) is invoked, it actually creates a new chunk of storage and allocates 20-byte-length buffer, while the original memory block reference count is reduced by 1. So when the code was executed, STR and test pointed to two different places, so it was peaceful.
Continued
(4) But here's a little note: Str. After GetBuffer (20), STR's allocation length is 20, that is, the pointer p it points to the buffer of only 20 bytes long, give it a value, must not exceed, otherwise disaster is not far from you; if the specified length is less than the original string length, such as GetBuffer (1), In fact, it allocates 4 byte lengths (that is, the original string length), and when the GetBuffer (...) is invoked. and change its content, be sure to remember to call ReleaseBuffer (), which updates the header information of the referenced memory block based on the string content.
(5) Finally there is a note to see the following code:
char* p = NULL;
Const char* q = NULL;
{
CString str = "ABCD";
Q = (LPCTSTR) str;
p = str. GetBuffer (20);
AfxMessageBox (q);/the Legal
strcpy (P, "This is Test");/Legal,
}
AfxMessageBox (q);//illegal, may be finished
strcpy (P, "This is Test");//illegal, possibly ruined.
The point here is that when these pointers are returned, if the CString object life ends, the pointers are also invalidated.
The following shows a code execution procedure
void Test ()
{
CString Str ("ABCD");//str point to a reference memory block (the reference count for a reference memory block is 1,
Length is 4, allocation length is 4)
CString a;//a points to an initial data state,
a = str; A and Str point to the same reference memory block (the reference count of reference memory blocks is 2,
Length is 4, allocation length is 4)
CString B (a);//a, B and Str point to the same reference memory block (reference to a reference memory block)
Count is 3, length is 4, allocation length is 4)
{
LPCTSTR temp = (LPCTSTR) a;//temp point to the string header of the reference memory block.
(Reference memory block reference count is 3, length is 4, allocation length is 4)
CString d = A; A, B, D and Str point to the same reference memory block (reference memory block reference count is 4, length is 4, allocation length is 4)
b = "Testa"; This statement actually calls the cstring::operator= (cstring&) function.
B points to a new allocated reference memory block. (The newly allocated reference memory block
Reference count is 1, length is 5, allocation length is 5)
At the same time the original reference memory block reference count minus 1. A, D and Str still point to the original
Reference memory block (reference memory block references count is 3, length is 4, allocation length is 4)
}//due to the end of D life, call the destructor and lead to the reference count minus 1 (reference memory
The reference count for the block is 2, the length is 4, and the allocation length is 4.
LPTSTR temp = A.getbuffer (10);//This statement also causes a new memory block to be reassigned.
Temp points to the first address of the new allocated reference memory block (new
The reference count for the allocated reference memory block is 1, length
is 0, allocating length is 10)
At the same time the original reference memory block reference count minus 1. Only STR is still
Point to the original reference memory block (reference memory block refers to the count of 1,
Length is 4, allocation length is 4)
strcpy (temp, "temp"); A refers to a reference memory block with a reference count of 1, a length of 0, and an allocation length of 10
A.releasebuffer ()//NOTE: A reference memory block to point to a reference count of 1, length 4, allocation length of 10
}
Execution to this, all the local variable life cycle has ended. Object STR a B each invokes its own destructor
function, the reference memory block that you point to also minus 1
Note that the count of the reference memory blocks that Str a B points to is 0, which causes the allocated memory block to be freed
By observing the above execution process, we will find that although multiple objects can point to the same reference CString, they are very intelligent and secure in making various copies, assigning values and changing the contents of a string, and are completely independent of each other and do not interfere with each other. Of course, you must require that your code be used correctly, especially in the actual use of more complex situations, such as the function parameters, references, and sometimes need to save to cstringlist, if even a small piece of local use, the result will cause unpredictable error
5 Effect of FreeExtra ()
Look at this code.
(1) CString str ("test");
(2) LPTSTR temp = str. GetBuffer (50);
(3) strcpy (temp, "There are character");
(4) Str. ReleaseBuffer ();
(5) Str. FreeExtra ();
When the above code executes to line (4), it is known that Str points to a reference memory block count of 1, a length of 22, and an allocation length of 50. Then execute str. When FreeExtra (), it frees up the extra memory that is allocated. (Reference memory block count is 1, length is 22, allocation length is 22)
6 Format (...) With FORMATV (...)
This statement is the most error-prone in use. Because it is the most skillful, but also quite flexible. Here, I do not intend to analyze it carefully, actually sprintf (...) How to use, it is how to use. I only need to pay attention to the use of a point: it is the specificity of the parameters, because the compiler in the compilation can not verify the format string parameters and the corresponding variable type and length. So you have to be aware that the two must correspond,
Otherwise there will be an error. Such as:
CString str;
int a = 12;
Str. Format ("first:%l, Second:%s", A, "error"); try it,//result?
Continued
7 LockBuffer () and UnlockBuffer ()
as implies, the functions of which are to lock and unlock reference memory blocks.
But what is the effect of using it and what effect it has on the CString string after it has been executed. Actually quite simple, look at the following code:
(1) CString str ("test");
(2) str. LockBuffer ();
(3) CString temp = str;
(4) str. UnlockBuffer ();
(5) str. LockBuffer ();
(6) str = "error";
(7) str. ReleaseBuffer (); After
finishes (3), unlike usual, temp and STR do not point to the same reference memory block. You can look at the Watch window with this expression (cstringdata*) (cstringdata*) (Str.m_pchdata)-1).
is actually in the MSDN Note:
while in a locked state, the string is Prote CTED in two ways:
No other string can get a reference to the the "data in the" locked string, even if that string was assigned to the locked string .
The locked string would never reference another string, even if that's the other string are copied to the locked string.
8 CString just handling strings.
No, CString not only can manipulate strings, but can also handle memory block data. function Perfect bar. Look at this code.
Char p[20];
for (int loop=0; loop<sizeof (P); loop++)
{
P[loop] = 10-loop;
}
CString Str ((LPCTSTR) p, 20);
Char temp[20];
memcpy (temp, str, str.) GetLength ());
STR is fully capable of reproducing memory block p into the memory block temp. So we can use CString to handle binary data.
8 allocsysstring () and setsysstring (bstr*)
These two functions provide a string-and-BSTR conversion. Note: When you call AllocSysString (), you must call it sysfreestring (...)
Safety test of 9 parameters
Multiple macros are provided in MFC to perform security checks on parameters, such as ASSERT. This is no exception in CString, there are many such parameters test, in fact, this also illustrates the security of the code is high, but sometimes we will find this annoying, but also cause debug and release version is not the same, such as sometimes the program debug normal, and releases the program crashes; , debug not, release line. In fact, I personally think that our use of CString, we should strive for high code quality, can not appear in the debug version of any assertion box, even if the release run seems to
Everything looks fine. But it's not safe. The following code:
(1) CString str ("test");
(2) Str. LockBuffer ();
(3) LPTSTR temp = str. GetBuffer (10);
(4) strcpy (temp, "error");
(5) Str. ReleaseBuffer ();
(6) Str. ReleaseBuffer ()///execute to this point, the debug version will play an error box
CString exception Handling
I just want to stress that only when allocating memory can it cause the cmemoryexception to be thrown.
Also, in the function declarations in MSDN, Functions with throw (cmemoryexception) have the possibility of reassigning or adjusting memory.
&NBSP
11 CString when the module is spanned. What happens when an argument in an interface function of a DLL is a cstring&. Answer the
questions I encountered. My question has already been posted, the address is: http://www.csdn.net/expert/topic/741/741921.xml?temp=.2283136
Constructs a CString object such as CString str, do you know the reference memory block that STR is pointing at at this time? Perhaps you would think it pointed to null. In fact, if this is the case, CString the reference mechanism used to manage the memory block will be in trouble, so CString in the construction of an empty string object, it will point to a fixed initialization address, this piece of data declaration is as follows:
afx_ static_data int _afxinitdata[] = { -1,0,0,0};
Brief Description: When a CString object string is empty, such as empty (), CString A, and so on, its member variable m_pchdata points to the address of the variable _afxinitdata. When the CString object lifecycle ends, it normally goes minus 1 to the reference memory block count pointed to, and frees the reference memory if the reference count is 0 (that is, there is no CString reference). The situation now is that if the reference memory block that CString points to is initializing a block of memory, no memory will be freed.
Having said so much, it has nothing to do with the problems I have encountered. It's really a big relationship. The real reason is that if the EXE module and the DLL module have a
is a static compile connection. So this CString initialization data has a different address in the EXE module and DLL module because the static connection will have a copy of the source code in this module. In another case, if all two modules are share connected, the CString implementation code is implemented in a separate DLL, and the afx_static_data specified variable is loaded once, so _afxinitdata in the two modules have the same address.
Now the question is fully understood. You can show it to yourself.
__declspec (dllexport) void Test (cstring& str)
{
str = "ABDEFAKDFJ";//if it is a static connection and the incoming STR is an empty string, there is an error.
}
The last point of thought: written here, in fact, there are many good CString skills, I did not explain. such as many overloaded operators, lookup, and so on. I think it's better to look at MSDN in more detail than I can say. I only focus on those situations that can make mistakes. Of course, I describe if there is a mistake, please master guidance, thank you.
This article from: I Love Research and Development Network (52rd.com)-R&d base
Detailed Source: http://www.52rd.com/Blog/Detail_RD.Blog_pollux_zy_3871.html