?? ch24.htm
字號(hào):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--
function popUp(pPage) {
var fullURL = document.location;
var textURL = fullURL.toString();
var URLlen = textURL.length;
var lenMinusPage = textURL.lastIndexOf("/");
lenMinusPage += 1;
var fullPath = textURL.substring(0,lenMinusPage);
popUpWin = window.open('','popWin','resizable=yes,scrollbars=no,width=525,height=394');
figDoc= popUpWin.document;
zhtm= '<HTML><HEAD><TITLE>' + pPage + '</TITLE>';
zhtm += '<link rel="stylesheet" href="/includes/stylesheets/ebooks.css"></head>';
zhtm += '<BODY bgcolor="#FFFFFF">';
zhtm += '<IMG SRC="' + fullPath + pPage + '">';
zhtm += '<P><B>' + pPage + '</B>';
zhtm += '</BODY></HTML>';
window.popUpWin.document.write(zhtm);
window.popUpWin.document.close();
// Johnny Jackson 4/28/98
}
//-->
</SCRIPT>
<link rel="stylesheet" href="/includes/stylesheets/ebooks.css">
<TITLE>Special Edition Using Visual C++ 6 -- Ch 24 -- Improving Your Application's Performance</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<CENTER>
<H1><IMG SRC="../button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
Special Edition Using Visual C++ 6</H1>
</CENTER>
<CENTER>
<P><A HREF="../ch23/ch23.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"
ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch25/ch25.htm"><IMG
SRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"
BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>
<HR>
</CENTER>
<CENTER>
<H1>- 24 -</H1>
<H1>Improving Your Application's Performance</H1>
</CENTER>
<UL>
<LI><A HREF="#Heading1">Preventing Errors with ASSERT and TRACE</A>
<UL>
<LI><A HREF="#Heading2">ASSERT: Detecting Logic Errors</A>
<LI><A HREF="#Heading3">TRACE: Isolating Problem Areas in Your Program</A>
</UL>
<LI><A HREF="#Heading4">Adding Debug-Only Features</A>
<LI><A HREF="#Heading5">Sealing Memory Leaks</A>
<UL>
<LI><A HREF="#Heading6">Common Causes of Memory Leaks</A>
<LI><A HREF="#Heading7">Debug new and delete</A>
<LI><A HREF="#Heading8">Automatic Pointers</A>
</UL>
<LI><A HREF="#Heading9">Using Optimization to Make Efficient Code</A>
<LI><A HREF="#Heading10">Finding Bottlenecks by Profiling</A>
</UL>
<P>
<HR SIZE="4">
<CENTER>
<H1></H1>
</CENTER>
<P>When developing a new application, there are various challenges developers must
meet. You need your application to compile, to run without blowing up, and you must
be sure that it does what you want it to do. On some projects, there is time to determine
whether your application can run faster and use less memory or whether you can have
a smaller executable file. The performance improvement techniques discussed in this
chapter can prevent your program from blowing up and eliminate the kind of thinkos
that result in a program calculating or reporting the wrong numbers. These improvements
are not merely final tweaks and touch-ups on a finished product.</P>
<P>You should form the habit of adding an ounce of prevention to your code as you
write and the habit of using the debugging capabilities that Developer Studio provides
you to confirm what's going on in your program. If you save all your testing to the
end, both the testing and the bug-fixing will be much harder than if you had been
testing all along. Also, of course, any bug you manage to prevent will never have
to be fixed at all!</P>
<P>
<H2><A NAME="Heading1"></A>Preventing Errors with ASSERT and TRACE</H2>
<P>The developers of Visual C++ did not invent the concepts of asserting and tracing.
Other languages support these ideas, and they are taught in many computer science
courses. What is exciting about the Visual C++ implementation of these concepts is
the clear way in which your results are presented and the ease with which you can
suppress assertions and TRACE statements in release versions of your application.</P>
<P>
<H3><A NAME="Heading2"></A>ASSERT: Detecting Logic Errors</H3>
<P>The ASSERT macro enables you to check a condition that you logically believe should
always be TRUE. For example, imagine you are about to access an array like this:</P>
<P>
<PRE>array[i] = 5;
</PRE>
<P>You want to be sure that the index, i, isn't less than zero and larger than the
number of elements allocated for the array. Presumably you have already written code
to calculate i, and if that code has been written properly, i must be between 0 and
the array size. An ASSERT statement will verify that:</P>
<P>
<PRE>ASSERT( i > 0 && i < ARRAYSIZE)
</PRE>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> There is no semicolon (;) at the end of the line because ASSERT is
a macro, not a function. Older C programs may call a function named assert(), but
you should replace these calls with the ASSERT macro because ASSERT disappears during
a release build, as discussed later in this section. 
<HR>
</BLOCKQUOTE>
<P>You can check your own logic with ASSERT statements. They should never be used
to check for user input errors or bad data in a file. Whenever the condition inside
an ASSERT statement is FALSE, program execution halts with a message telling you
which assertion failed. At this point, you know you have a logic error, or a developer
error, that you need to correct. Here's another example:</P>
<P>
<PRE>// Calling code must pass a non-null pointer
void ProcessObject( Foo * fooObject )
{
ASSERT( fooObject )
// process object
}
</PRE>
<P>This code can dereference the pointer in confidence, knowing execution will be
halted if the pointer is NULL.</P>
<P>You probably already know that Developer Studio makes it simple to build debug
and release versions of your programs. The debug version #defines a constant, _DEBUG,
and macros and other pre-processor code can check this constant to determine the
build type. When _DEBUG isn't defined, the ASSERT macro does nothing. This means
there is no speed constraint in the final code, as there would be if you added if
statements yourself to test for logic errors. There is no need for you to go through
your code, removing ASSERT statements when you release your application, and, in
fact, it's better to leave them there to help the developers who work on version
2. They document your assumptions, and they'll be there when the debugging work starts
again. In addition, ASSERT can't help you if there is a problem with the release
version of your code because it is used to find logic and design errors before you
release version 1.0 of your product.</P>
<P>
<H3><A NAME="Heading3"></A>TRACE: Isolating Problem Areas in Your Program</H3>
<P>As discussed in Appendix D, "Debugging," the power of the Developer
Studio debugger is considerable. You can step through your code one line at a time
or run to a breakpoint, and you can see any of your variables' values in watch windows
as you move through the code. This can be slow, however, and many developers use
TRACE statements as a way of speeding up this process and zeroing in on the problem
area. Then they turn to more traditional step-by-step debugging to isolate the bad
code.</P>
<P>In the old days, isolating bad code meant adding lots of print statements to your
program, which is problematic in a Windows application. Before you start to think
up workarounds, such as printing to a file, relax. The TRACE macro does everything
you want, and like ASSERT, it magically goes away in release builds.</P>
<P>There are several TRACE macros: TRACE, TRACE0, TRACE1, TRACE2, and TRACE3. The
number-suffix indicates the number of parametric arguments beyond a simple string,
working much like printf. The different versions of TRACE were implemented to save
data segment space.</P>
<P>When you generate an application with AppWizard, many ASSERT and TRACE statements
are added for you. Here's a TRACE example:</P>
<P>
<PRE>if (!m_wndToolBar.Create(this)
|| !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
</PRE>
<P>If the creation of the toolbar fails, this routine will return -1, which signals
to the calling program that something is wrong. This will happen in both debug and
release builds. In debug builds, though, a trace output will be sent to help the
programmer understand what went wrong.</P>
<P>All the TRACE macros write to afxDump, which is usually the debug window, but
can be set to stderr for console applications. The number-suffix indicates the parametric
argument count, and you use the parametric values within the string to indicate the
passed data type--for example, to send a TRACE statement that includes the value
of an integer variable:</P>
<P>
<PRE>TRACE1("Error Number: %d\n", -1 );
</PRE>
<P>or to pass two arguments, maybe a string and an integer:</P>
<P>
<PRE>TRACE2("File Error %s, error number: %d\n", __FILE__, -1 );
</PRE>
<P>The most difficult part of tracing is making it a habit. Sprinkle TRACE statements
anywhere you return error values: before ASSERT statements and in areas where you
are unsure that you constructed your code correctly. When confronted with unexpected
behavior, add TRACE statements first so that you better understand what is going
on before you start debugging.</P>
<P>
<H2><A NAME="Heading4"></A>Adding Debug-Only Features</H2>
<P>If the idea of code that isn't included in a release build appeals to you, you
may want to arrange for some of your own code to be included in debug builds but
not in release builds. It's easy. Just wrap the code in a test of the _DEBUG constant,
like this:</P>
<P>
<PRE>#ifdef _DEBUG
// debug code here
#endif
</PRE>
<P>In release builds, this code will not be compiled at all.</P>
<P>All the settings and configurations of the compiler and linker are kept separately
for debug and release builds and can be changed independently. For example, many
developers use different compiler warning levels. To bump your warning level to 4
for debug builds only, follow these steps:</P>
<P>
<DL>
<DT></DT>
<DD><B>1. </B>Choose Project, Settings, which opens the Project Settings dialog box,
shown in Figure 24.1.
<P>
<DT></DT>
<DD><B>2. </B>Choose Debug or Release from the drop-down list box at the upper left.
If you choose All Configurations, you'll change debug and release settings simultaneously.
<P>
<DT></DT>
<DD><B>3. </B>Click the C/C++ tab and set the Warning Level to Level 4, as shown
in Figure 24.2. The default is Level 3, which you will use for the release version
(see Figure 24.3).
<P>
</DL>
<P>Warning level 4 will generate a lot more errors than level 3. Some of those errors
will probably come from code you didn't even write, such as MFC functions. You'll
just have to ignore those warnings.</P>
<P><A HREF="javascript:popUp('24uvc01.gif')"><B>FIG. 24.1</B></A><B> </B><I>The Project
Settings dialog box enables you to set configuration items for different phases of
development.</I></P>
<P><A HREF="javascript:popUp('24uvc02.gif')"><B>FIG. 24.2</B></A><B> </B><I>Warning
levels can be set higher during development.</I></P>
<P><A HREF="javascript:popUp('24uvc03.gif')"><B>FIG. 24.3</B></A><B> </B><I>Warning
levels are usually lower in a production release.</I></P>
<P><I></I>
<H2><A NAME="Heading5"></A>Sealing Memory Leaks</H2>
<P>A memory leak can be the most pernicious of errors. Small leaks may not cause
any execution errors in your program until it is run for an exceptionally long time
or with a larger-than-usual data file. Because most programmers test with tiny data
files or run the program for only a few minutes when they are experimenting with
parts of it, memory leaks may not reveal themselves in everyday testing. Alas, memory
leaks may well reveal themselves to your users when the program crashes or otherwise
misbehaves.</P>
<P>
<H3><A NAME="Heading6"></A>Common Causes of Memory Leaks</H3>
<P>What does it mean when your program has a memory leak? It means that your program
allocated memory and never released it. One very simple cause is calling new to allocate
an object or an array of objects on the heap and never calling delete. Another cause
is changing the pointer kept in a variable without deleting the memory the pointer
was pointing to. More subtle memory leaks arise when a class with a pointer as a
member variable calls new to assign the pointer but doesn't have a copy constructor,
assignment operator, or destructor. Listing 24.1 illustrates some ways that memory
leaks are caused.</P>
<P>
<H4>Listing 24.1  Causing Memory Leaks</H4>
<PRE>// simple pointer leaving scope
{
int * one = new int;
*one = 1;
} // one is out of scope now, and wasn't deleted
// mismatched new and delete: new uses delete and new[] uses delete[]
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -