📄 ei3.htm
字号:
<!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 3: Prefer new and delete to malloc and free</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 = "EI3_DIR.HTM";
var dingtext = "Item E3, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E3: Prefer new and delete to malloc and free" -->
<A NAME="1838"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI2_FR.HTM" TARGET="_top">Item 2: Prefer <iostream> to <stdio.h>.</A> <BR> Continue to <A HREF="./EI4_FR.HTM" TARGET="_top">Item 4: Prefer C++-style comments.</A></FONT></DIV>
<P><A NAME="dingp1"></A><FONT ID="eititle">Item 3: Prefer <CODE>new</CODE> and <CODE>delete</CODE> to <CODE>malloc</CODE> and <CODE>free</CODE>.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="1839"></A>
<P><A NAME="dingp2"></A>
The problem with <CODE>malloc</CODE> and <CODE>free</CODE> (and their variants) is simple: they don't know about constructors and <NOBR>destructors.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="1840"></A>
<P><A NAME="dingp3"></A>
Consider the following two ways to get space for an array of 10 <CODE>string</CODE> objects, one using <CODE>malloc</CODE>, the other using <CODE>new</CODE>:<SCRIPT>create_link(3);</SCRIPT>
</P>
<A NAME="1842"></A>
<UL><PRE>string *stringArray1 =
static_cast<string*>(malloc(10 * sizeof(string)));
</PRE>
</UL><A NAME="1843"></A>
<UL><PRE>string *stringArray2 = new string[10];
</PRE>
</UL><A NAME="1844"></A>
<P><A NAME="dingp4"></A>
Here <CODE>stringArray1</CODE> points to enough memory for 10 <CODE>string</CODE> objects, but no objects have been constructed in that memory. Furthermore, without jumping through some rather obscure linguistic hoops (such as those described in Items <A HREF="../MEC/MI4_FR.HTM#5218" TARGET="_top">M4</A> and <A HREF="../MEC/MI8_FR.HTM#33985" TARGET="_top">M8</A>), you have no way to initialize the objects in the array. In other words, <CODE>stringArray1</CODE> is pretty useless. In contrast, <CODE>stringArray2</CODE> points to an array of 10 fully constructed <CODE>string</CODE> objects, each of which can safely be used in any operation taking a <CODE>string</CODE>.<SCRIPT>create_link(4);</SCRIPT>
</P>
<A NAME="1845"></A>
<P><A NAME="dingp5"></A>
Nonetheless, let's suppose you magically managed to initialize the objects in the <CODE>stringArray1</CODE> array. Later on in your program, then, you'd expect to do <NOBR>this:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="1846"></A>
<UL><PRE>free(stringArray1);
</PRE>
</UL><A NAME="1847"></A>
<UL><PRE>
delete [] stringArray2; // see <A HREF="./EI5_FR.HTM#1869" TARGET="_top">Item 5</A> for why the
// "[]" is necessary
</PRE>
</UL><A NAME="1848"></A>
<P><A NAME="dingp6"></A>
The call to <CODE>free</CODE> will release the memory pointed to by <CODE>stringArray1</CODE>, but no destructors will be called on the <CODE>string</CODE> objects in that mem<A NAME="p20"></A>ory. If the <CODE>string</CODE> objects themselves allocated memory, as <CODE>string</CODE> objects are wont to do, all the memory they allocated will be lost. On the other hand, when <CODE>delete</CODE> is called on <CODE>stringArray2</CODE>, a destructor is called for each object in the array before any memory is <NOBR>released.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="1849"></A>
<P><A NAME="dingp7"></A>
Because <CODE>new</CODE> and <CODE>delete</CODE> interact properly with constructors and destructors, they are clearly the superior <NOBR>choice.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="104344"></A>
<P><A NAME="dingp8"></A>
Mixing <CODE>new</CODE> and <CODE>delete</CODE> with <CODE>malloc</CODE> and <CODE>free</CODE> is usually a bad idea. When you try to call <CODE>free</CODE> on a pointer you got from <CODE>new</CODE> or call <CODE>delete</CODE> on a pointer you got from <CODE>malloc</CODE>, the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' <NOBR>faces.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="13170"></A>
<P><A NAME="dingp9"></A>
The incompatibility of <CODE>new</CODE>/<CODE>delete</CODE> and <CODE>malloc</CODE>/<CODE>free</CODE> can lead to some interesting complications. For example, the <CODE>strdup</CODE> function commonly found in <CODE><string.h></CODE> takes a <CODE>char*</CODE>-based string and returns a copy of <NOBR>it:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="1851"></A>
<UL><PRE>
char * strdup(const char *ps); // return a copy of what
// ps points to
</PRE>
</UL><A NAME="1852"></A>
<P><A NAME="dingp10"></A>
At some sites, both C and C++ use the same version of <CODE>strdup</CODE>, so the memory allocated inside the function comes from <CODE>malloc</CODE>. As a result, unwitting C++ programmers calling <CODE>strdup</CODE> might overlook the fact that they must use <CODE>free</CODE> on the pointer returned from <CODE>strdup</CODE>. But wait! To forestall such complications, some sites might decide to rewrite <CODE>strdup</CODE> for C++ and have this rewritten version call <CODE>new</CODE> inside the function, thereby mandating that callers later use <CODE>delete</CODE>. As you can imagine, this can lead to some pretty nightmarish portability problems as code is shuttled back and forth between sites with different forms of <CODE>strdup</CODE>.<SCRIPT>create_link(10);</SCRIPT>
</P>
<A NAME="12827"></A>
<P><A NAME="dingp11"></A>
Still, C++ programmers are as interested in code reuse as C programmers, and it's a simple fact that there are lots of C libraries based on <CODE>malloc</CODE> and <CODE>free</CODE> containing code that is very much worth reusing. When taking advantage of such a library, it's likely you'll end up with the responsibility for <CODE>free</CODE>ing memory <CODE>malloc</CODE>ed by the library and/or <CODE>malloc</CODE>ing memory the library itself will <CODE>free</CODE>. That's fine. There's nothing wrong with calling <CODE>malloc</CODE> and <CODE>free</CODE> inside a C++ program as long as you make sure the pointers you get from <CODE>malloc</CODE> always meet their maker in <CODE>free</CODE> and the pointers you get from <CODE>new</CODE> eventually find their way to <CODE>delete</CODE>. The problems start when you get sloppy and try to mix <CODE>new</CODE> with <CODE>free</CODE> or <CODE>malloc</CODE> with <CODE>delete</CODE>. That's just asking for <NOBR>trouble.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="1853"></A>
<P><A NAME="dingp12"></A>
<A NAME="p21"></A>Given that <CODE>malloc</CODE> and <CODE>free</CODE> are ignorant of constructors and destructors and that mixing <CODE>malloc</CODE>/<CODE>free</CODE> with <CODE>new</CODE>/<CODE>delete</CODE> can be more volatile than a fraternity rush party, you're best off sticking to an exclusive diet of <CODE>new</CODE>s and <CODE>delete</CODE>s whenever you <NOBR>can.<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI2_FR.HTM" TARGET="_top">Item 2: Prefer <iostream> to <stdio.h>.</A> <BR> Continue to <A HREF="./EI4_FR.HTM" TARGET="_top">Item 4: Prefer C++-style comments.</A></FONT></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -