>5 O! r8 l: q5 C6 e4 x8 b- s, \2 _6 C( ~
>This article contains a list of suggestions put together by the members of TeamB for C++Builder. The suggestions will help you avoid subtle coding errors that often have disastrous effects at runtime. Most of the suggestions in the list contain a link to a paragraph of text that explains why you should follow the suggestion. Some of the suggestions are self explanatory, and these suggestions don't have a corresponding link. </P>
>Note: Updated Feb 21, 2000. New items have a NEW icon.</P>
>4 L5 A, S4 O9 u
>
>4 r4 n8 R- @: s$ U
>
>
>
>
>
> AnsiString strText = "Howdy Mr. Ditka.";
>This code contains a serious defect. If you execute this code, you will see that the label displays the first string that was assigned to strText. This may surprise you. Why doesn't the label contain the string that says "Goodbye Mr. Ditka"? After all, doesn't ptr point to the string that is contained in the strText variable? </P>$ A& |7 i2 D7 ?* F
>Whenever you assign a new string to an AnsiString variable, the AnsiString deallocates whatever memory it previously owned and allocates new memory for the new string. When the new memory is allocated, it is unlikely to be the same memory that was originally returned by the c_str function. </P>3 O8 J4 l! T! R7 d: Z* j
>The second line of code in the example above stores the pointer returned by c_str for later use. After the pointer is stored, a new string is assigned to the AnsiString variable. At this point, the strText variable deallocates the first string and allocates memory for the new string. Now ptr points to memory that has been deleted. When you copy that memory into the label, you see the remnants of the original string. For larger strings, the label may contain garbage characters, or the label may appear to be truncated. De-referencing the data in the ptr variable may also cause an access violation because you are using memory that the application no longer owns. </P>
>Storing the result of c_str can lead to problems that are more difficult to track down. For example: </P>1 c, ]- [/ Y2 S$ |
> char *ptr1 = Edit1->Text.c_str();+ ]; _" r4 L% D) B. l
> Label1->Caption = "Edit1 contains " + AnsiString(ptr1);
>On the surface, the code looks like it should work. Sure, we store the pointer returned from c_str, but nothing is done that would cause the string to be re-allocated as in the first example. However, if you test this code, you will see that it does not work. Sometimes the labels will both display the string from the second edit box, and sometimes they contain garbage. </P>
>The problem is that the Text property of TEdit returnes a new AnsiString by value. This new AnsiString object is a temporary object. Temporary objects don't last forever. They only hang around as long as they are needed. They are destroyed before the next line of code executes. </P>* v: a* s5 \& Y5 R7 ^2 ?
>In this code example, the temporary object is only needed for the call to c_str. Once the c_str method has been called, the temporary object is destroyed because it is no longer needed. Here is the catch. Deleting the temporary object deletes the memory that was pointed to by c_str, which means that ptr1 points to deleted memory. You can see the destruction of the temporary object by viewing the assembly code generated by these statements. </P>
> // assembly output for the statement5 ^& {6 p- Q! P
> mov ..., |3 t, Z u& K% Z
>All of this code is generated by the one statement where ptr1 is assigned the value of Edit1->Text.c_str(). Before the next line of code executes, the temporary AnsiString object is destroyed. Deleting the temporary AnsiString object renders the previous c_str result worthless, and that is exactly what happens (and it's exactly what should happen, the compiler is obeying the standard by cleaning up temporary objects in this manner). </P>2 q. D# ~ D- A$ i6 X. Q
>The moral of this story is to avoid saving the result from AnsiString::c_str because you run the risk of keeping a pointer to memory that has been de-allocated. </P>
>/ ^. p8 ]0 ?+ Y5 y# z( p
>
> __fastcall AnsiString::AnsiString(unsigned long src) : Data(0)) d. F; M: n1 e5 o& a( ^
>The last line should be *this = buff; The bug is fixed in BCB4 and newer. </P>
>2 q, @0 y" r. Z- G1 R5 P1 p+ N
perator += // combine the two strings9 I' ^. h6 [& J# a
oCreate. OK, so who calls DoCreate? It is called from one of two places depending on the value of the OldCreateOrder property. If OldCreateOrder is false (ie the good setting), then DoCreate is called from TCustomForm.AfterConstruction. AfterConstruction executes immediately after all of the constructors for your form have finished running (how this happens can be attributed to compiler magic). The second function that calls DoCreate is TCustomForm::Create, the pascal constructor for the form. </P>
estroy so that it sets the datalink objects to nil after deleting them. If you heeded the advice about not using the built in data aware controls, then you can fix the Destroy function by changing it as shown below. </P>| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |