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

📄 ei33.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 33: Use inlining judiciously</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI33_DIR.HTM";
var dingtext = "Item E33, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E33: Use inlining judiciously." -->
<A NAME="25939"></A><A NAME="6729"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI32_FR.HTM" TARGET="_top">Item 32: Postpone variable definitions as long as possible.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI34_FR.HTM" TARGET="_top">Item 34: Minimize compilation dependencies between files.</A></FONT></DIV>

<P><A NAME="dingp1"></A><FONT ID="eititle">Item 33: &nbsp;Use inlining judiciously.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="6730"></A>
<P><A NAME="dingp2"></A>
Inline functions -- what a <I>wonderful</I> idea! They look like functions, they act like functions, they're ever so much better than macros (see <A HREF="./EI1_FR.HTM#1790" TARGET="_top">Item 1</A>), and you can call them without having to incur the overhead of a function call. What more could you possibly ask <NOBR>for?<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="6735"></A>
<P><A NAME="dingp3"></A>
You actually get more than you might think, because avoiding the cost of a function call is only half the story. Compiler optimization routines are typically designed to concentrate on stretches of code that lack function calls, so when you inline a function, you may enable compilers to perform context-specific optimizations on the body of the function. Such optimizations would be impossible for "normal" function <NOBR>calls.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="6737"></A>
<P><A NAME="dingp4"></A>
However, let's not get carried away. In programming, as in life, there is no free lunch, and inline functions are no exception. The whole idea behind an inline function is to replace each call of that function with its code body, and it doesn't take a Ph.D. in statistics to see that this is likely to increase the overall size of your object code. On machines with limited memory, overzealous inlining can give rise to programs that are too big for the available space. Even with virtual memory, inline-induced code bloat can lead to pathological paging behavior (thrashing) that will slow your program to a crawl. (It will, however, provide your disk controller with a nice exercise regimen.) Too much <a name="p138"></a>inlining can also reduce your instruction cache hit rate, thus reducing the speed of instruction fetch from that of cache memory to that of primary <NOBR>memory.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="6739"></A>
<P><A NAME="dingp5"></A>
On the other hand, if an inline function body is <I>very</I> short, the code generated for the function body may actually be smaller than the code generated for a function call. If that is the case, inlining the function may actually lead to <I>smaller</I> object code and a higher cache hit <NOBR>rate!<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="6741"></A>
<P><A NAME="dingp6"></A>
Bear in mind that the <CODE>inline</CODE> directive, like <CODE>register</CODE>, is a <I>hint</I> to compilers, not a command. That means compilers are free to ignore your inline directives whenever they want to, and it's not that hard to make them want to. For example, most compilers refuse to inline "complicated" functions (e.g., those that contain loops or are recursive), and all but the most trivial virtual function calls stop inlining routines dead in their tracks. (This shouldn't be much of a surprise. <CODE>virtual</CODE> means "wait until runtime to figure out which function to call," and <CODE>inline</CODE> means "during compilation, replace the call site with the called function." If compilers don't know which function will be called, you can hardly blame them for refusing to make an inline call to it.) It all adds up to this: whether a given inline function is actually inlined is dependent on the implementation of the compiler you're using. Fortunately, most compilers have a diagnostic level that will result in a warning (see <A HREF="./EI48_FR.HTM#8378" TARGET="_top">Item 48</A>) if they fail to inline a function you've asked them <NOBR>to.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="6750"></A>
<P><A NAME="dingp7"></A>
Suppose you've written some function <CODE>f</CODE> and you've declared it <CODE>inline</CODE>. What happens if a compiler chooses, for whatever reason, not to inline that function? The obvious answer is that <CODE>f</CODE> will be treated like a non-inline function: code for <CODE>f</CODE> will be generated as if it were a normal "outlined" function, and calls to <CODE>f</CODE> will proceed as normal function <NOBR>calls.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="18543"></A>
<P><A NAME="dingp8"></A>
In theory, this is precisely what will happen, but this is one of those occasions when theory and practice may go their separate ways. That's because this very tidy solution to the problem of what to do about "outlined inlines" was added to C++ relatively late in the standardization process. Earlier specifications for the language (such as the ARM &#151; see <A HREF="./EI50_FR.HTM#8569" TARGET="_top">Item 50</A>) told compiler vendors to implement different behavior, and the older behavior is still common enough that you need to understand what it <NOBR>is.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="6751"></A>
<P><A NAME="dingp9"></A>
Think about it for a minute, and you'll realize that inline function definitions are virtually always put in header files. This allows multiple translation units (source files) to include the same header files and reap the advantages of the inline functions that are defined within them. Here's an example, in which I adopt the convention that source files end in ".cpp"; this is probably the most prevalent of the file naming conventions in the world of <NOBR>C++:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<a name="p139"></a>
<UL><PRE><A NAME="6755"></A>
 // This is file example.h
 inline void f() { ... }	 	        // definition of f
</PRE>
</UL>
<UL><PRE><A NAME="6756"></A>
 ...
</PRE>
</UL>
<A NAME="6757"></A>
<UL><PRE><A NAME="6758"></A>
 // This is file source1.cpp
 #include "example.h"	 	 	 // includes definition of f
 	 	 	                    // contains calls to f</PRE>
</UL>
<UL><PRE><A NAME="6759"></A>
 ...
</PRE>
</UL>
<A NAME="6760"></A>
<UL><PRE><A NAME="6761"></A>
 // This is file source2.cpp
 #include "example.h"	 	 	 // also includes definition
	                   	 	 	 // of f
						 // also calls f
 ...
</PRE>
</UL>
<UL><PRE><A NAME="19386"></A>

</PRE>
</UL></P>
<A NAME="6762"></A>
<P><A NAME="dingp10"></A>
Under the old "outlined inline" rules and the assumption that <CODE>f</CODE> is <I>not</I> being inlined, when <CODE>source1.cpp</CODE> is compiled, the resulting object file will contain a function called <CODE>f</CODE>, just as if <CODE>f</CODE> had never been declared <CODE>inline</CODE>. Similarly, when <CODE>source2.cpp</CODE> is compiled, its generated object file will also hold a function called <CODE>f</CODE>. When you try to link the two object files together, you can reasonably expect your linker to complain that your program contains two definitions of <CODE>f</CODE>, an <NOBR>error.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>
<A NAME="6764"></A>
<P><A NAME="dingp11"></A>
To prevent this problem, the old rules decreed that compilers treat an un-inlined inline function as if the function had been declared <CODE>static</CODE> &#151; that is, local to the file currently being compiled. In the example you just saw, compilers following the old rules would treat <CODE>f</CODE> as if it were static in <CODE>source1.cpp</CODE> when that file was being compiled and as if it were static in <CODE>source2.cpp</CODE> when that file was being compiled. This strategy eliminates the link-time problem, but at a cost: each translation unit that includes the definition of <CODE>f</CODE> (and that calls <CODE>f</CODE>) contains its own static copy of <CODE>f</CODE>. If <CODE>f</CODE> itself defines local static variables, each copy of <CODE>f</CODE> gets its <I>own copy</I> of the variables, something sure to astonish programmers who believe that "<CODE>static</CODE>" inside a function means "only one <NOBR>copy."<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="6766"></A>
<P><A NAME="dingp12"></A>
This leads to a stunning realization. Under both new rules and old, if an inline function isn't inlined, you <I>still</I> pay for the cost of a function call at each call site, but under the old rules, you can <I>also</I> suffer an increase in code size, because each translation unit that includes and calls <CODE>f</CODE> gets its own copy of <CODE>f</CODE>'s code and <CODE>f</CODE>'s static variables! (To make matters worse, each copy of <CODE>f</CODE> and each copy of <CODE>f</CODE>'s static variables tend to end up on different virtual memory pages, so two calls to different copies of <CODE>f</CODE> are likely to entail one or more page <NOBR>faults.)<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="6768"></A>
<P><A NAME="dingp13"></A>
<a name="p140"></a>
There's more. Sometimes your poor, embattled compilers have to generate a function body for an inline function even when they are perfectly willing to inline the function. In particular, if your program ever takes the address of an inline function, compilers must generate a function body for it. How can they come up with a pointer to a function that doesn't <NOBR>exist?<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P><UL><PRE><A NAME="6770"></A>
inline void f() {...}            // as above
</PRE>
</UL>

<UL><PRE><A NAME="6771"></A>
void (*pf)() = f;                // pf points to f
</PRE>
</UL>

<UL><PRE><A NAME="6772"></A>
int main()
{
  f();                           // an inline call to f
</PRE>

⌨️ 快捷键说明

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