⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 suggest.htm

📁 C++builder学习资料C++builder
💻 HTM
📖 第 1 页 / 共 4 页
字号:


<HTML>

<HEAD>

   <TITLE> The TeamB guide to avoiding common mistakes in C++Builder.</TITLE>

   <META NAME="Author" CONTENT="Harold Howe">

</HEAD>

<BODY>



<CENTER>

<TABLE  BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH="640">

<TR>



<TD>









<H3>

The TeamB guide to avoiding common mistakes in C++Builder.

</H3>



<P>

This article contains a list of suggestions put together by the members of 

<A TARGET=_top HREF="http://www.inprise.com/newsgroups/teamb/teambbyproduct.html">TeamB for C++Builder</A>. 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> 

 

<P><B>Note:</B> Updated Feb 21, 2000. New items have a <B>NEW</B> icon.</P> 

<OL> 

<LI>AnsiString 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">1.1</TD><TD><A HREF="#cstr"        >Don't store the result of AnsiString::c_str()</A>          </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">1.2</TD><TD><A HREF="#unsignedlong">Don't use the unsigned long constructor for AnsiString</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">1.3</TD><TD><A HREF="#ansiproperty">Don't use the += AnsiString operator on properties</A></TD></TR> 

    </TABLE> 

    <br> 

 

<LI>TList 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">2.1</TD><TD><A HREF="#tlist"         >Don't forget to delete pointers in a TList</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">2.2</TD><TD><A HREF="#voidptr"       >Don't delete the void pointers in a TList</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">2.3</TD><TD><A HREF="#overuse_tlist" >Don't overuse the TList class</A></TD></TR> 

    </TABLE> 

    <BR> 

 

<LI> General VCL suggestions 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.1</TD><TD>Don't Change the Name property of a control at runtime                                           </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.2</TD><TD><A HREF="#parent"    >Don't forget to set the Parent property of a control created at runtime</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.3</TD><TD><A HREF="#mdiparent" >Don't set the Parent property of MDI child forms</A>                       </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.4</TD><TD>Don't forget to call Synchronize when modifying visual controls in a background thread           </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.5</TD><TD>Don't delete child controls after their parent is gone                                           </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.6</TD><TD>Don't pass parameters by reference to property methods                                           </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.7</TD><TD>Don't use the Selected property of TListBox in single selection ListBox controls                 </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.8</TD><TD>Don't try to put more than 32k of text into a TMemo on Win95/Win98                               </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.9</TD><TD><A HREF="#oncreate"  >Don't use OnCreate and OnDestroy, use C++ constructors and destructors instead</a></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">3.10</TD><TD><A HREF="#createform" >Use <TT>new</TT> instead of Application-&gt;CreateForm</a></TD></TR> 

    </TABLE> 

    <BR> 

 

<LI> C++ Language Suggestions 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">4.1</TD><TD>Don't mix operator new[] with delete, and don't mix delete[] with new                  </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">4.2</TD><TD><A HREF="#nullptr"    >Always set a pointer variable to NULL or 0 after deleting it</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">4.3</TD><TD>Don't use memset or ZeroMemory as constructor replacements                             </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">4.4</TD><TD>Don't make assumptions about the size of an enum variable                              </TD></TR> 

    </TABLE> 

    <BR> 

 

<LI> Project Suggestions 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">5.1</TD><TD><IMG SRC="../../../CBOOK/1111/images/new.gif" BORDER=0 ALIGN="BOTTOM" width="29" height="12"><A HREF="#makefile" >Don't alter the makefile switches for alignment or enum variables</A>               </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">5.2</TD><TD><A HREF="#vclib"    >Don't link with LIB files or OBJ files created by other compilers</A>               </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">5.3</TD><TD><A HREF="#bclib"    >Don't link with OBJ files created by a previous version of the Borland compiler</A> </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">5.4</TD><TD><A HREF="#tlibimp"  >Don't import COM type libraries using the IDE menu option</A>                       </TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">5.5</TD><TD><IMG SRC="../../../CBOOK/1111/images/new.gif" BORDER=0 ALIGN="BOTTOM" width="29" height="12"><A HREF="#oldcreateorder">When you import BCB3 forms into BCB4, set OldCreateOrder to false</A></TD></TR> 

    </TABLE> 

 

     <BR> 

<LI> Database Suggestions 

    <TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.1</TD><TD><A HREF="#asfunction"    >Don't use AsDateTime or AsInteger to assign one TField to another</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.2</TD><TD><A HREF="#currency"      >Don't use TCurrencyField unless you have to</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.3</TD><TD><A HREF="#cachedfilter"  >Don't turn on CachedUpdates when the Filtered property of dataset is on</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.4</TD><TD><A HREF="#updatefilter"  >Don't call ApplyUpdates when the Filtered property of dataset is on</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.5</TD><TD><A HREF="#dataaware"     >Don't use the VCL's data aware controls</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.6</TD><TD><IMG SRC="../../../CBOOK/1111/images/new.gif" BORDER=0 ALIGN="BOTTOM" width="29" height="12"><A HREF="#lookupcontrols">Don't use TDBLookupComboBox or TDBLookupListBox</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.7</TD><TD><A HREF="#active"        >Don't set the Active property of a dataset to true at design time</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.8</TD><TD><A HREF="#filteredit"    >Don't change the Filter property of a dataset while the dataset is in edit mode</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.9</TD><TD><A HREF="#updatestatus"  >Don't look at the value of UpdateStatus in the OnUpdateRecord handler of a dataset</A></TD></TR> 

    <TR> <TD WIDTH=5% ALIGN="LEFT" VALIGN="TOP">6.10</TD><TD><IMG SRC="../../../CBOOK/1111/images/new.gif" BORDER=0 ALIGN="BOTTOM" width="29" height="12"><A HREF="#disablecontrols" >Don't call Post after calling DisableControls on a dataset</A></TD></TR> 

    </TABLE> 

    <BR> 

</OL> 

 

 

 

<BR> 

<H3> 

<A NAME="cstr">Don't store the result of AnsiString::c_str()</A> 

</H3> 

<P> 

Examine the following code segment. 

</P> 

<pre>

    AnsiString strText <b>=</b> <font color="blue">&quot;Howdy Mr. Ditka.&quot;</font><b>;</b>

    <b>char</b> <b>*</b>ptr <b>=</b> strText<b>.</b>c_str<b>(</b><b>)</b><b>;</b>

    strText <b>=</b> <font color="blue">&quot;Goodbye Mr. Ditka&quot;</font><b>;</b>

    Label1<b>-&gt;</b>Caption <b>=</b> ptr<b>;</b>

</pre> 

<P> 

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 <TT>strText</TT>. This may surprise you. Why doesn't the label contain the string that says 

"Goodbye Mr. Ditka"? After all, doesn't <TT>ptr</TT> point to the string that is contained in the <TT>strText</TT> 

variable? 

</P> 

<P> 

Whenever you assign a new string to an <TT>AnsiString</TT> variable, the <TT>AnsiString</TT> 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 <TT>c_str</TT> function. 

</P> 

<P> 

The second line of code in the example above stores the pointer returned by <TT>c_str</TT> for later use. After the 

pointer is stored, a new string is assigned to the <TT>AnsiString</TT> variable. At this point, the <TT>strText</TT> 

variable deallocates the first string and allocates memory for the new string. Now <TT>ptr</TT> 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 

<TT>ptr</TT> variable may also cause an access violation because you are using memory that the application no longer 

owns. 

</P> 

<P> 

Storing the result of <TT>c_str</TT> can lead to problems that are more difficult to track down. For example: 

</P> 

<pre>

    <b>char</b> <b>*</b>ptr1 <b>=</b> Edit1<b>-&gt;</b>Text<b>.</b>c_str<b>(</b><b>)</b><b>;</b>

    <b>char</b> <b>*</b>ptr2 <b>=</b> Edit2<b>-&gt;</b>Text<b>.</b>c_str<b>(</b><b>)</b><b>;</b>



    Label1<b>-&gt;</b>Caption <b>=</b> <font color="blue">&quot;Edit1 contains &quot;</font> <b>+</b> AnsiString<b>(</b>ptr1<b>)</b><b>;</b>

    Label2<b>-&gt;</b>Caption <b>=</b> <font color="blue">&quot;Edit2 contains &quot;</font> <b>+</b> AnsiString<b>(</b>ptr2<b>)</b><b>;</b>

</pre> 

<P> 

On the surface, the code looks like it should work. Sure, we store the pointer returned from <TT>c_str</TT>, 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> 

<P> 

The problem is that the <TT>Text</TT> property of <TT>TEdit</TT> returnes a new <TT>AnsiString</TT> by value. This new 

<TT>AnsiString</TT> 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> 

<P> 

In this code example, the temporary object is only needed for the call to <TT>c_str.</TT> Once the <TT>c_str</TT> 

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 <TT>c_str</TT>, which means that <TT>ptr1</TT> points 

to deleted memory. You can see the destruction of the temporary object by viewing the assembly code generated by these 

statements. 

</P> 

<PRE>

    // assembly output for the statement

    <B>char</B> *ptr1 = Edit1-&gt;Text.c_str();



    mov   ...

    lea   ...

    call  System::AnsiString::AnsiString(); // create temp object

    mov   ...

    inc   ...

    mov   ...

    call  Controls::TControl::GetText();    // load Caption into temp AnsiString

    lea   ...

    call  System::AnsiString::c_str()       // get c_str of temp object

    mov   ...

    dec   ...

    lea   ...

    mov   ...

    call  System::AnsiString::~AnsiString   // delete temp object

</PRE> 

<P> 

All of this code is generated by the one statement where <TT>ptr1</TT> is assigned the value of 

<TT>Edit1->Text.c_str()</TT>. Before the next line of code executes, the temporary <TT>AnsiString</TT> object is 

destroyed. Deleting the temporary <TT>AnsiString</TT> object renders the previous <TT>c_str</TT> 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> 

<P> 

The moral of this story is to avoid saving the result from <TT>AnsiString::c_str</TT> because you run the risk of 

keeping a pointer to memory that has been de-allocated. 

</P> 

 

 

<BR> 

<H3> 

<A NAME="unsignedlong">Don't use the unsigned long constructor for AnsiString</A> 

</H3> 

<P> 

If you are using C++Builder 3, the unsigned long constructor for <TT>AnsiString</TT> has a bug in it. The bug looks 

like this: 

</P> 

<pre>

    <b>__fastcall</b> AnsiString<b>:</b><b>:</b>AnsiString<b>(</b><b>unsigned</b> <b>long</b> src<b>)</b> <b>:</b> Data<b>(</b><font color="blue">0</font><b>)</b>

    <b>{</b>

        <b>char</b> buff<b>[</b><font color="blue">20</font><b>]</b><b>;</b>

        wsprintf<b>(</b>buff<b>,</b> <font color="blue">&quot;%lu&quot;</font><b>,</b> src<b>)</b><b>;</b>

        <b>*</b><b>this</b> <b>=</b> src<b>;</b>

    <b>}</b>

</pre> 

<P> 

The last line should be <TT>*this = buff;</TT> The bug is fixed in BCB4 and newer. 

</P> 

 

 

<BR> 

<H3> 

<A NAME="ansiproperty">Don't use the += AnsiString operator on properties</A> 

</H3> 

<P> 

Examine the following code that attempts to add some exclamation points to the string that is already in a label control: 

</P> 

<pre>

    Label1<b>-&gt;</b>Caption <b>+</b><b>=</b> <font color="blue">&quot;!!!!!!!&quot;</font><b>;</b>

</pre> 

<P> 

When you use the += operator on the <TT>Caption</TT> property, the compiler creates code that constructs a new 

temporary <TT>AnsiString</TT> object. The compiler then calls the <TT>GetText</TT> function to copy the contents of 

the label into the temporary variable. Next, the compiler constructs another <TT>AnsiString</TT> object and initializes 

it with the string "!!!!!". Finally, the compiler calls the += operator of the first temporary object to combine the two 

strings. The problem is that the compiler does not generator code to write the resulting temporary <TT>AnsiString</TT> 

value back into the <TT>Caption</TT> property. Instead, the temporary object is deleted because it is no longer needed. 

</P> 

<P>The assembly code looks something like this:</P> 

<PRE>

    // assembly output for the statement

    Label1-&gt;Caption += &quot;!!!!!!!&quot;;



    mov   ...

    lea   ...

    call  System::AnsiString::AnsiString() // create temp object

    mov   ...

    inc   ...

    mov   ...

    mov   ...

    call  Controls::TControl::GetText()    // read Caption into temp object

    lea   ...

    push  ...

    mov   ...

    lea   ...

    call  System::AnsiString::AnsiString(char *) // create AnsiString for &quot;!!!!&quot;

    inc   ...

    lea   ...

    pop   ...

    call  System::AnsiString::operator +=        // combine the two strings

    dec   ...

    lea   ...

    mov   ...

    call  System::AnsiString::~AnsiString() // destroy one temp

    dec   ...

    lea   ...

    mov   ...

    call  System::AnsiString::~AnsiString() // destroy the other temp

</PRE> 

<P> 

In the assembly code above, locate the += operator call. Notice that nothing is done with the resulting string 

after the += operator returns. After the += operator returns, the strings are destroyed. In order for the property 

assignment to take affect, the resulting string should be passed to the <TT>SetText</TT> function. Because the write 

method for the property is not called, the <TT>TLabel</TT> object is not modified. 

</P> 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -