home *** CD-ROM | disk | FTP | other *** search
/ ftp.pasteur.org/FAQ/ / ftp-pasteur-org-FAQ.zip / FAQ / C++-faq / part6 < prev    next >
Text File  |  2000-03-01  |  45KB  |  1,233 lines

  1. Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news-out.cwix.com!newsfeed.cwix.com!newsfeed2.skycache.com!newsfeed.skycache.com!news.maxwell.syr.edu!newsfeed.novia.net.MISMATCH!novia!nntp3.cerf.net!nntp2.cerf.net!news.cerf.net!not-for-mail
  2. From: mpcline@nic.cerf.net (Marshall Cline)
  3. Newsgroups: comp.lang.c++,comp.answers,news.answers,alt.comp.lang.learn.c-c++
  4. Subject: C++ FAQ (part 6 of 10)
  5. Followup-To: comp.lang.c++
  6. Date: 29 Feb 2000 20:06:59 GMT
  7. Organization: ATT Cerfnet
  8. Lines: 1212
  9. Approved: news-answers-request@mit.edu
  10. Distribution: world
  11. Expires: +1 month
  12. Message-ID: <89h8t3$bu0$1@news.cerf.net>
  13. Reply-To: cline@parashift.com (Marshall Cline)
  14. NNTP-Posting-Host: nic1.san.cerf.net
  15. X-Trace: news.cerf.net 951854819 12224 192.215.81.88 (29 Feb 2000 20:06:59 GMT)
  16. X-Complaints-To: abuse@cerf.net
  17. NNTP-Posting-Date: 29 Feb 2000 20:06:59 GMT
  18. Summary: Please read this before posting to comp.lang.c++
  19. Xref: senator-bedfellow.mit.edu comp.lang.c++:453813 comp.answers:39853 news.answers:178212 alt.comp.lang.learn.c-c++:40791
  20.  
  21. Archive-name: C++-faq/part6
  22. Posting-Frequency: monthly
  23. Last-modified: Feb 29, 2000
  24. URL: http://marshall-cline.home.att.net/cpp-faq-lite/
  25.  
  26. AUTHOR: Marshall Cline / cline@parashift.com / 972-931-9470
  27.  
  28. COPYRIGHT: This posting is part of "C++ FAQ Lite."  The entire "C++ FAQ Lite"
  29. document is Copyright(C)1991-2000 Marshall Cline, Ph.D., cline@parashift.com.
  30. All rights reserved.  Copying is permitted only under designated situations.
  31. For details, see section [1].
  32.  
  33. NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS.  THE AUTHOR PROVIDES NO
  34. WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING
  35. WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
  36. PURPOSE.
  37.  
  38. C++-FAQ-Lite != C++-FAQ-Book: This document, C++ FAQ Lite, is not the same as
  39. the C++ FAQ Book.  The book (C++ FAQs, Cline and Lomow, Addison-Wesley) is 500%
  40. larger than this document, and is available in bookstores.  For details, see
  41. section [3].
  42.  
  43. ==============================================================================
  44.  
  45. SECTION [16]: Freestore management
  46.  
  47.  
  48. [16.1] Does delete p delete the pointer p, or the pointed-to-data *p?
  49.  
  50. The pointed-to-data.
  51.  
  52. The keyword should really be delete_the_thing_pointed_to_by.  The same abuse of
  53. English occurs when freeing the memory pointed to by a pointer in C: free(p)
  54. really means free_the_stuff_pointed_to_by(p).
  55.  
  56. ==============================================================================
  57.  
  58. [16.2] Can I free() pointers allocated with new? Can I delete pointers
  59.        allocated with malloc()?
  60.  
  61. No!
  62.  
  63. It is perfectly legal, moral, and wholesome to use malloc() and delete in the
  64. same program, or to use new and free() in the same program.  But it is illegal,
  65. immoral, and despicable to call free() with a pointer allocated via new, or to
  66. call delete on a pointer allocated via malloc().
  67.  
  68. Beware! I occasionally get e-mail from people telling me that it works OK for
  69. them on machine X and compiler Y.  That does not make it right! Sometimes
  70. people say, "But I'm just working with an array of char." Nonetheless do not
  71. mix malloc() and delete on the same pointer, or new and free() on the same
  72. pointer! If you allocated via p = new char[n], you must use delete[] p; you
  73. must not use free(p).  Or if you allocated via p = malloc(n), you must use
  74. free(p); you must not use delete[] p or delete p! Mixing these up could cause a
  75. catastrophic failure at runtime if the code was ported to a new machine, a new
  76. compiler, or even a new version of the same compiler.
  77.  
  78. You have been warned.
  79.  
  80. ==============================================================================
  81.  
  82. [16.3] Why should I use new instead of trustworthy old malloc()?
  83.  
  84. Constructors/destructors, type safety, overridability.
  85.  * Constructors/destructors: unlike malloc(sizeof(Fred)), new Fred() calls
  86.    Fred's constructor.  Similarly, delete p calls *p's destructor.
  87.  * Type safety: malloc() returns a void* which isn't type safe.  new Fred()
  88.    returns a pointer of the right type (a Fred*).
  89.  * Overridability: new is an operator that can be overridden by a class, while
  90.    malloc() is not overridable on a per-class basis.
  91.  
  92. ==============================================================================
  93.  
  94. [16.4] Can I use realloc() on pointers allocated via new?
  95.  
  96. No!
  97.  
  98. When realloc() has to copy the allocation, it uses a bitwise copy operation,
  99. which will tear many C++ objects to shreds.  C++ objects should be allowed to
  100. copy themselves.  They use their own copy constructor or assignment operator.
  101.  
  102. Besides all that, the heap that new uses may not be the same as the heap that
  103. malloc() and realloc() use!
  104.  
  105. ==============================================================================
  106.  
  107. [16.5] Do I need to check for NULL after p = new Fred()?
  108.  
  109. No! (But if you have an old compiler, you may have to force the compiler to
  110. have this behavior[16.6]).
  111.  
  112. It turns out to be a real pain to always write explicit NULL tests after every
  113. new allocation.  Code like the following is very tedious:
  114.  
  115.     Fred* p = new Fred();
  116.     if (p == NULL)
  117.       throw bad_alloc();
  118.  
  119. If your compiler doesn't support (or if you refuse to use) exceptions[17], your
  120. code might be even more tedious:
  121.  
  122.     Fred* p = new Fred();
  123.     if (p == NULL) {
  124.       cerr << "Couldn't allocate memory for a Fred" << endl;
  125.       abort();
  126.     }
  127.  
  128. Take heart.  In C++, if the runtime system cannot allocate sizeof(Fred) bytes
  129. of memory during p = new Fred(), a bad_alloc exception will be thrown.  Unlike
  130. malloc(), new never returns NULL!
  131.  
  132. Therefore you should simply write:
  133.  
  134.     Fred* p = new Fred();   // No need to check if p is NULL
  135.  
  136. However, if your compiler is old, it may not yet support this.  Find out by
  137. checking your compiler's documentation under "new".  If you have an old
  138. compiler, you may have to force the compiler to have this behavior[16.6].
  139.  
  140. ==============================================================================
  141.  
  142. [16.6] How can I convince my (older) compiler to automatically check new to see
  143.        if it returns NULL?
  144.  
  145. Eventually your compiler will.
  146.  
  147. If you have an old compiler that doesn't automagically perform the NULL
  148. test[16.5], you can force the runtime system to do the test by installing a
  149. "new handler" function.  Your "new handler" function can do anything you want,
  150. such as print a message and abort() the program, delete some objects and return
  151. (in which case operator new will retry the allocation), throw an exception,
  152. etc.
  153.  
  154. Here's a sample "new handler" that prints a message and calls abort().  The
  155. handler is installed using set_new_handler():
  156.  
  157.     #include <new.h>        // To get set_new_handler
  158.     #include <stdlib.h>     // To get abort()
  159.     #include <iostream.h>   // To get cerr
  160.  
  161.     void myNewHandler()
  162.     {
  163.       // This is your own handler.  It can do anything you want.
  164.       cerr << "Attempt to allocate memory failed!" << endl;
  165.       abort();
  166.     }
  167.  
  168.     int main()
  169.     {
  170.       set_new_handler(myNewHandler);   // Install your "new handler"
  171.       // ...
  172.     }
  173.  
  174. After the set_new_handler() line is executed, operator new will call your
  175. myNewHandler() if/when it runs out of memory.  This means that new will never
  176. return NULL:
  177.  
  178.     Fred* p = new Fred();   // No need to check if p is NULL
  179.  
  180. Note: Please use this abort() approach as a last resort.  If your compiler
  181. supports exception handling[17], please consider throwing an exception instead
  182. of calling abort().
  183.  
  184. Note: If some global/static object's constructor uses new, it won't use the
  185. myNewHandler() function since that constructor will get called before main()
  186. begins.  Unfortunately there's no convenient way to guarantee that the
  187. set_new_handler() will be called before the first use of new.  For example,
  188. even if you put the set_new_handler() call in the constructor of a global
  189. object, you still don't know if the module ("compilation unit") that contains
  190. that global object will be elaborated first or last or somewhere inbetween.
  191. Therefore you still don't have any guarantee that your call of
  192. set_new_handler() will happen before any other global's constructor gets
  193. invoked.
  194.  
  195. ==============================================================================
  196.  
  197. [16.7] Do I need to check for NULL before delete p?
  198.  
  199. No!
  200.  
  201. The C++ language guarantees that delete p will do nothing if p is equal to
  202. NULL.  Since you might get the test backwards, and since most testing
  203. methodologies force you to explicitly test every branch point, you should not
  204. put in the redundant if test.
  205.  
  206. Wrong:
  207.  
  208.     if (p != NULL)
  209.       delete p;
  210.  
  211. Right:
  212.  
  213.     delete p;
  214.  
  215. ==============================================================================
  216.  
  217. [16.8] What are the two steps that happen when I say delete p?
  218.  
  219. delete p is a two-step process: it calls the destructor, then releases the
  220. memory.  The code generated for delete p looks something like this (assuming p
  221. is of type Fred*):
  222.  
  223.     // Original code: delete p;
  224.     if (p != NULL) {
  225.       p->~Fred();
  226.       operator delete(p);
  227.     }
  228.  
  229. The statement p->~Fred() calls the destructor for the Fred object pointed to by
  230. p.
  231.  
  232. The statement operator delete(p) calls the memory deallocation primitive,
  233. void operator delete(void* p).  This primitive is similar in spirit to
  234. free(void* p).  (Note, however, that these two are not interchangeable; e.g.,
  235. there is no guarantee that the two memory deallocation primitives even use the
  236. same heap!).
  237.  
  238. ==============================================================================
  239.  
  240. [16.9] In p = new Fred(), does the Fred memory "leak" if the Fred constructor
  241.        throws an exception?
  242.  
  243. No.
  244.  
  245. If an exception occurs during the Fred constructor of p = new Fred(), the C++
  246. language guarantees that the memory sizeof(Fred) bytes that were allocated will
  247. automagically be released back to the heap.
  248.  
  249. Here are the details: new Fred() is a two-step process:
  250.  
  251.  1. sizeof(Fred) bytes of memory are allocated using the primitive
  252.     void* operator new(size_t nbytes).  This primitive is similar in spirit to
  253.     malloc(size_t nbytes).  (Note, however, that these two are not
  254.     interchangeable; e.g., there is no guarantee that the two memory allocation
  255.     primitives even use the same heap!).
  256.  
  257.  2. It constructs an object in that memory by calling the Fred constructor.
  258.     The pointer returned from the first step is passed as the this parameter to
  259.     the constructor.  This step is wrapped in a try ... catch block to handle
  260.     the case when an exception is thrown during this step.
  261.  
  262. Thus the actual generated code looks something like:
  263.  
  264.     // Original code: Fred* p = new Fred();
  265.     Fred* p = (Fred*) operator new(sizeof(Fred));
  266.     try {
  267.       new(p) Fred();       // Placement new[11.10]
  268.     } catch (...) {
  269.       operator delete(p);  // Deallocate the memory
  270.       throw;               // Re-throw the exception
  271.     }
  272.  
  273. The statement marked "Placement new[11.10]" calls the Fred constructor.  The
  274. pointer p becomes the this pointer inside the constructor, Fred::Fred().
  275.  
  276. ==============================================================================
  277.  
  278. [16.10] How do I allocate / unallocate an array of things?
  279.  
  280. Use p = new T[n] and delete[] p:
  281.  
  282.     Fred* p = new Fred[100];
  283.     // ...
  284.     delete[] p;
  285.  
  286. Any time you allocate an array of objects via new (usually with the [n] in the
  287. new expression), you must use [] in the delete statement.  This syntax is
  288. necessary because there is no syntactic difference between a pointer to a thing
  289. and a pointer to an array of things (something we inherited from C).
  290.  
  291. ==============================================================================
  292.  
  293. [16.11] What if I forget the [] when deleteing array allocated via new T[n]?
  294.  
  295. All life comes to a catastrophic end.
  296.  
  297. It is the programmer's --not the compiler's-- responsibility to get the
  298. connection between new T[n] and delete[] p correct.  If you get it wrong,
  299. neither a compile-time nor a run-time error message will be generated by the
  300. compiler.  Heap corruption is a likely result.  Or worse.  Your program will
  301. probably die.
  302.  
  303. ==============================================================================
  304.  
  305. [16.12] Can I drop the [] when deleteing array of some built-in type (char,
  306.         int, etc)?
  307.  
  308. No!
  309.  
  310. Sometimes programmers think that the [] in the delete[] p only exists so the
  311. compiler will call the appropriate destructors for all elements in the array.
  312. Because of this reasoning, they assume that an array of some built-in type such
  313. as char or int can be deleted without the [].  E.g., they assume the following
  314. is valid code:
  315.  
  316.     void userCode(int n)
  317.     {
  318.       char* p = new char[n];
  319.       // ...
  320.       delete p;     // <-- ERROR! Should be delete[] p !
  321.     }
  322.  
  323. But the above code is wrong, and it can cause a disaster at runtime.  In
  324. particular, the code that's called for delete p is operator delete(void*), but
  325. the code that's called for delete[] p is operator delete[](void*).  The default
  326. behavior for the latter is to call the former, but users are allowed to replace
  327. the latter with a different behavior (in which case they would normally also
  328. replace the corresponding new code in operator new[](size_t)).  If they
  329. replaced the delete[] code so it wasn't compatible with the delete code, and
  330. you called the wrong one (i.e., if you said delete p rather than delete[] p),
  331. you could end up with a disaster at runtime.
  332.  
  333. ==============================================================================
  334.  
  335. [16.13] After p = new Fred[n], how does the compiler know there are n objects
  336.         to be destructed during delete[] p?
  337.  
  338. Short answer: Magic.
  339.  
  340. Long answer: The run-time system stores the number of objects, n, somewhere
  341. where it can be retrieved if you only know the pointer, p.  There are two
  342. popluar techniques that do this.  Both these techniques are in use by
  343. commercial grade compilers, both have tradeoffs, and neither is perfect.  These
  344. techniques are:
  345.  * Over-allocate the array and put n just to the left of the first Fred
  346.    object[33.6].
  347.  * Use an associative array with p as the key and n as the value[33.7].
  348.  
  349. ==============================================================================
  350.  
  351. [16.14] Is it legal (and moral) for a member function to say delete this?
  352.  
  353. As long as you're careful, it's OK for an object to commit suicide (delete
  354. this).
  355.  
  356. Here's how I define "careful":
  357.  
  358.  1. You must be absolutely 100% positive sure that this object was allocated
  359.     via new (not by new[], nor by placement new[11.10], nor a local object on
  360.     the stack, nor a global, nor a member of another object; but by plain
  361.     ordinary new).
  362.  
  363.  2. You must be absolutely 100% positive sure that your member function will be
  364.     the last member function invoked on this object.
  365.  
  366.  3. You must be absolutely 100% positive sure that the rest of your member
  367.     function (after the delete this line) doesn't touch any piece of this
  368.     object (including calling any other member functions or touching any data
  369.     members).
  370.  
  371.  4. You must be absolutely 100% positive sure that no one even touches the this
  372.     pointer itself after the delete this line.  In other words, you must not
  373.     examine it, compare it with another pointer, compare it with NULL, print
  374.     it, cast it, do anything with it.
  375.  
  376. Naturally the usual caveats apply in cases where your this pointer is a pointer
  377. to a base class when you don't have a virtual destructor[20.4].
  378.  
  379. ==============================================================================
  380.  
  381. [16.15] How do I allocate multidimensional arrays using new?
  382.  
  383. There are many ways to do this, depending on how flexible you want the array
  384. sizing to be.  On one extreme, if you know all the dimensions at compile-time,
  385. you can allocate multidimensional arrays statically (as in C):
  386.  
  387.     class Fred { /*...*/ };
  388.     void someFunction(Fred& fred);
  389.  
  390.     void manipulateArray()
  391.     {
  392.       const unsigned nrows = 10;  // Num rows is a compile-time constant
  393.       const unsigned ncols = 20;  // Num columns is a compile-time constant
  394.       Fred matrix[nrows][ncols];
  395.  
  396.       for (unsigned i = 0; i < nrows; ++i) {
  397.         for (unsigned j = 0; j < ncols; ++j) {
  398.           // Here's the way you access the (i,j) element:
  399.           someFunction( matrix[i][j] );
  400.  
  401.           // You can safely "return" without any special delete code:
  402.           if (today == "Tuesday" && moon.isFull())
  403.             return;     // Quit early on Tuesdays when the moon is full
  404.         }
  405.       }
  406.  
  407.       // No explicit delete code at the end of the function either
  408.     }
  409.  
  410. More commonly, the size of the matrix isn't known until run-time but you know
  411. that it will be rectangular.  In this case you need to use the heap
  412. ("freestore"), but at least you are able to allocate all the elements in one
  413. freestore chunk.
  414.  
  415.     void manipulateArray(unsigned nrows, unsigned ncols)
  416.     {
  417.       Fred* matrix = new Fred[nrows * ncols];
  418.  
  419.       // Since we used a simple pointer above, we need to be VERY
  420.       // careful to avoid skipping over the delete code.
  421.       // That's why we catch all exceptions:
  422.       try {
  423.  
  424.         // Here's how to access the (i,j) element:
  425.         for (unsigned i = 0; i < nrows; ++i) {
  426.           for (unsigned j = 0; j < ncols; ++j) {
  427.             someFunction( matrix[i*ncols + j] );
  428.           }
  429.         }
  430.  
  431.         // If you want to quit early on Tuesdays when the moon is full,
  432.         // make sure to do the delete along ALL return paths:
  433.         if (today == "Tuesday" && moon.isFull()) {
  434.           delete[] matrix;
  435.           return;
  436.         }
  437.  
  438.         // ...
  439.  
  440.       }
  441.       catch (...) {
  442.         // Make sure to do the delete when an exception is thrown:
  443.         delete[] matrix;
  444.         throw;    // Re-throw the current exception
  445.       }
  446.  
  447.       // Make sure to do the delete at the end of the function too:
  448.       delete[] matrix;
  449.     }
  450.  
  451. Finally at the other extreme, you may not even be guaranteed that the matrix is
  452. rectangular.  For example, if each row could have a different length, you'll
  453. need to allocate each row individually.  In the following function, ncols[i] is
  454. the number of columns in row number i, where i varies between 0 and nrows-1
  455. inclusive.
  456.  
  457.     void manipulateArray(unsigned nrows, unsigned ncols[])
  458.     {
  459.       Fred** matrix = new Fred*[nrows];
  460.       for (unsigned i = 0; i < nrows; ++i)
  461.         matrix[i] = new Fred[ ncols[i] ];
  462.  
  463.       // Since we used a simple pointer above, we need to be VERY
  464.       // careful to avoid skipping over the delete code.
  465.       // That's why we catch all exceptions:
  466.       try {
  467.  
  468.         // Here's how to access the (i,j) element:
  469.         for (unsigned i = 0; i < nrows; ++i) {
  470.           for (unsigned j = 0; j < ncols[i]; ++j) {
  471.             someFunction( matrix[i][j] );
  472.           }
  473.         }
  474.  
  475.         // If you want to quit early on Tuesdays when the moon is full,
  476.         // make sure to do the delete along ALL return paths:
  477.         if (today == "Tuesday" && moon.isFull()) {
  478.           for (unsigned i = nrows; i > 0; --i)
  479.             delete[] matrix[i-1];
  480.           delete[] matrix;
  481.           return;
  482.         }
  483.  
  484.         // ...
  485.  
  486.       }
  487.       catch (...) {
  488.         // Make sure to do the delete when an exception is thrown:
  489.         for (unsigned i = nrows; i > 0; --i)
  490.           delete[] matrix[i-1];
  491.         delete[] matrix;
  492.         throw;    // Re-throw the current exception
  493.       }
  494.  
  495.       // Make sure to do the delete at the end of the function too.
  496.       // Note that deletion is the opposite order of allocation:
  497.       for (i = nrows; i > 0; --i)
  498.         delete[] matrix[i-1];
  499.       delete[] matrix;
  500.     }
  501.  
  502. Note the funny use of matrix[i-1] in the deletion process.  This prevents
  503. wrap-around of the unsigned value when i goes one step below zero.
  504.  
  505. Finally, note that pointers and arrays are evil[21.5].  It is normally much
  506. better to encapsulate your pointers in a class that has a safe and simple
  507. interface.  The following FAQ[16.16] shows how to do this.
  508.  
  509. ==============================================================================
  510.  
  511. [16.16] But the previous FAQ's code is SOOOO tricky and error prone! Isn't
  512.         there a simpler way?
  513.  
  514. Yep.
  515.  
  516. The reason the code in the previous FAQ[16.15] was so tricky and error prone
  517. was that it used pointers, and we know that pointers and arrays are evil[21.5].
  518. The solution is to encapsulate your pointers in a class that has a safe and
  519. simple interface.  For example, we can define a Matrix class that handles a
  520. rectangular matrix so our user code will be vastly simplified when compared to
  521. the the rectangular matrix code from the previous FAQ[16.15]:
  522.  
  523.     // The code for class Matrix is shown below...
  524.     void someFunction(Fred& fred);
  525.  
  526.     void manipulateArray(unsigned nrows, unsigned ncols)
  527.     {
  528.       Matrix matrix(nrows, ncols);   // Construct a Matrix called matrix
  529.  
  530.       for (unsigned i = 0; i < nrows; ++i) {
  531.         for (unsigned j = 0; j < ncols; ++j) {
  532.           // Here's the way you access the (i,j) element:
  533.           someFunction( matrix(i,j) );
  534.  
  535.           // You can safely "return" without any special delete code:
  536.           if (today == "Tuesday" && moon.isFull())
  537.             return;     // Quit early on Tuesdays when the moon is full
  538.         }
  539.       }
  540.  
  541.       // No explicit delete code at the end of the function either
  542.     }
  543.  
  544. The main thing to notice is the lack of clean-up code.  For example, there
  545. aren't any delete statements in the above code, yet there will be no memory
  546. leaks, assuming only that the Matrix destructor does its job correctly.
  547.  
  548. Here's the Matrix code that makes the above possible:
  549.  
  550.     class Matrix {
  551.     public:
  552.       Matrix(unsigned nrows, unsigned ncols);
  553.       // Throws a BadSize object if either size is zero
  554.       class BadSize { };
  555.  
  556.       // Based on the Law Of The Big Three[25.9]:
  557.      ~Matrix();
  558.       Matrix(const Matrix& m);
  559.       Matrix& operator= (const Matrix& m);
  560.  
  561.       // Access methods to get the (i,j) element:
  562.       Fred&       operator() (unsigned i, unsigned j);
  563.       const Fred& operator() (unsigned i, unsigned j) const;
  564.       // These throw a BoundsViolation object if i or j is too big
  565.       class BoundsViolation { };
  566.  
  567.     private:
  568.       Fred* data_;
  569.       unsigned nrows_, ncols_;
  570.     };
  571.  
  572.     inline Fred& Matrix::operator() (unsigned row, unsigned col)
  573.     {
  574.       if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
  575.       return data_[row*ncols_ + col];
  576.     }
  577.  
  578.     inline const Fred& Matrix::operator() (unsigned row, unsigned col) const
  579.     {
  580.       if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
  581.       return data_[row*ncols_ + col];
  582.     }
  583.  
  584.     Matrix::Matrix(unsigned nrows, unsigned ncols)
  585.       : data_  (new Fred[nrows * ncols]),
  586.         nrows_ (nrows),
  587.         ncols_ (ncols)
  588.     {
  589.       if (nrows == 0 || ncols == 0)
  590.         throw BadSize();
  591.     }
  592.  
  593.     Matrix::~Matrix()
  594.     {
  595.       delete[] data_;
  596.     }
  597.  
  598. Note that the above Matrix class accomplishes two things: it moves some tricky
  599. memory management code from the user code (e.g., main()) to the class, and it
  600. reduces the overall bulk of program (e.g., assuming Matrix is even mildly
  601. reusable, moving complexity from the users of Matrix into Matrix itself is
  602. equivalent to moving complexity from the many to the few).  And anyone who's
  603. seen Star Trek 3 knows that the good of the many outweighs the good of the
  604. few... or the one.
  605.  
  606. ==============================================================================
  607.  
  608. [16.17] But the above Matrix class is specific to Fred! Isn't there a way to
  609.         make it generic?
  610.  
  611. Yep; just use templates[31]:
  612.  
  613.     template<class T>  // See section on templates[31] for more
  614.     class Matrix {
  615.     public:
  616.       Matrix(unsigned nrows, unsigned ncols);
  617.       // Throws a BadSize object if either size is zero
  618.       class BadSize { };
  619.  
  620.       // Based on the Law Of The Big Three[25.9]:
  621.      ~Matrix();
  622.       Matrix(const Matrix<T>& m);
  623.       Matrix<T>& operator= (const Matrix<T>& m);
  624.  
  625.       // Access methods to get the (i,j) element:
  626.       T&       operator() (unsigned i, unsigned j);
  627.       const T& operator() (unsigned i, unsigned j) const;
  628.       // These throw a BoundsViolation object if i or j is too big
  629.       class BoundsViolation { };
  630.  
  631.     private:
  632.       T* data_;
  633.       unsigned nrows_, ncols_;
  634.     };
  635.  
  636.     template<class T>
  637.     inline T& Matrix<T>::operator() (unsigned row, unsigned col)
  638.     {
  639.       if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
  640.       return data_[row*ncols_ + col];
  641.     }
  642.  
  643.     template<class T>
  644.     inline const T& Matrix<T>::operator() (unsigned row, unsigned col) const
  645.     {
  646.       if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
  647.       return data_[row*ncols_ + col];
  648.     }
  649.  
  650.     template<class T>
  651.     inline Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
  652.       : data_  (new T[nrows * ncols]),
  653.         nrows_ (nrows),
  654.         ncols_ (ncols)
  655.     {
  656.       if (nrows == 0 || ncols == 0)
  657.         throw BadSize();
  658.     }
  659.  
  660.     template<class T>
  661.     inline Matrix<T>::~Matrix()
  662.     {
  663.       delete[] data_;
  664.     }
  665.  
  666. Here's one way to use this template[31]:
  667.  
  668.     #include "Fred.hpp"     // To get the definition for class Fred
  669.  
  670.     void doSomethingWith(Fred& fred);
  671.  
  672.     void sample(unsigned nrows, unsigned ncols)
  673.     {
  674.       Matrix<Fred> matrix(nrows, ncols);   // Construct a Matrix<Fred> called matrix
  675.  
  676.       for (unsigned i = 0; i < nrows; ++i) {
  677.         for (unsigned j = 0; j < ncols; ++j) {
  678.           doSomethingWith( matrix(i,j) );
  679.         }
  680.       }
  681.     }
  682.  
  683. ==============================================================================
  684.  
  685. [16.18] Does C++ have arrays whose length can be specified at run-time?
  686.  
  687. Yes, in the sense that STL[32.1] has a vector template that provides this
  688. behavior.
  689.  
  690. No, in the sense that built-in array types need to have their length specified
  691. at compile time.
  692.  
  693. Yes, in the sense that even built-in array types can specify the first index
  694. bounds at run-time.  E.g., comparing with the previous FAQ, if you only need
  695. the first array dimension to vary then you can just ask new for an array of
  696. arrays, rather than an array of pointers to arrays:
  697.  
  698.     const unsigned ncols = 100;           // ncols = number of columns in the array
  699.  
  700.     class Fred { /*...*/ };
  701.  
  702.     void manipulateArray(unsigned nrows)  // nrows = number of rows in the array
  703.     {
  704.       Fred (*matrix)[ncols] = new Fred[nrows][ncols];
  705.       // ...
  706.       delete[] matrix;
  707.     }
  708.  
  709. You can't do this if you need anything other than the first dimension of the
  710. array to change at run-time.
  711.  
  712. But please, don't use arrays unless you have to.  Arrays are evil[21.5].  Use
  713. some object of some class if you can.  Use arrays only when you have to.
  714.  
  715. ==============================================================================
  716.  
  717. [16.19] How can I force objects of my class to always be created via new rather
  718.         than as locals or global/static objects?
  719.  
  720. Use the Named Constructor Idiom[10.8].
  721.  
  722. As usual with the Named Constructor Idiom, the constructors are all private: or
  723. protected:, and there are one or more public static create() methods (the
  724. so-called "named constructors"), one per constructor.  In this case the
  725. create() methods allocate the objects via new.  Since the constructors
  726. themselves are not public, there is no other way to create objects of the
  727. class.
  728.  
  729.     class Fred {
  730.     public:
  731.       // The create() methods are the "named constructors":
  732.       static Fred* create()                 { return new Fred();     }
  733.       static Fred* create(int i)            { return new Fred(i);    }
  734.       static Fred* create(const Fred& fred) { return new Fred(fred); }
  735.       // ...
  736.  
  737.     private:
  738.       // The constructors themselves are private or protected:
  739.       Fred();
  740.       Fred(int i);
  741.       Fred(const Fred& fred);
  742.       // ...
  743.     };
  744.  
  745. Now the only way to create Fred objects is via Fred::create():
  746.  
  747.     int main()
  748.     {
  749.       Fred* p = Fred::create(5);
  750.       // ...
  751.       delete p;
  752.     }
  753.  
  754. Make sure your constructors are in the protected: section if you expect Fred to
  755. have derived classes.
  756.  
  757. Note also that you can make another class Wilma a friend[14] of Fred if you
  758. want to allow a Wilma to have a member object of class Fred, but of course this
  759. is a softening of the original goal, namely to force Fred objects to be
  760. allocated via new.
  761.  
  762. ==============================================================================
  763.  
  764. [16.20] How do I do simple reference counting?
  765.  
  766. If all you want is the ability to pass around a bunch of pointers to the same
  767. object, with the feature that the object will automagically get deleted when
  768. the last pointer to it disappears, you can use something like the following
  769. "smart pointer" class:
  770.  
  771.     // Fred.h
  772.  
  773.     class FredPtr;
  774.  
  775.     class Fred {
  776.     public:
  777.       Fred() : count_(0) /*...*/ { }  // All ctors set count_ to 0 !
  778.       // ...
  779.     private:
  780.       friend FredPtr;     // A friend class[14]
  781.       unsigned count_;
  782.       // count_ must be initialized to 0 by all constructors
  783.       // count_ is the number of FredPtr objects that point at this
  784.     };
  785.  
  786.     class FredPtr {
  787.     public:
  788.       Fred* operator-> () { return p_; }
  789.       Fred& operator* ()  { return *p_; }
  790.       FredPtr(Fred* p)    : p_(p) { ++p_->count_; }  // p must not be NULL
  791.      ~FredPtr()           { if (--p_->count_ == 0) delete p_; }
  792.       FredPtr(const FredPtr& p) : p_(p.p_) { ++p_->count_; }
  793.       FredPtr& operator= (const FredPtr& p)
  794.             { // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
  795.               // (This order properly handles self-assignment[12.1])
  796.               ++p.p_->count_;
  797.               if (--p_->count_ == 0) delete p_;
  798.               p_ = p.p_;
  799.               return *this;
  800.             }
  801.     private:
  802.       Fred* p_;    // p_ is never NULL
  803.     };
  804.  
  805. Naturally you can use nested classes to rename FredPtr to Fred::Ptr.
  806.  
  807. Note that you can soften the "never NULL" rule above with a little more
  808. checking in the constructor, copy constructor, assignment operator, and
  809. destructor.  If you do that, you might as well put a p_ != NULL check into the
  810. "*" and "->" operators (at least as an assert()).  I would recommend against an
  811. operator Fred*() method, since that would let people accidentally get at the
  812. Fred*.
  813.  
  814. One of the implicit constraints on FredPtr is that it must only point to Fred
  815. objects which have been allocated via new.  If you want to be really safe, you
  816. can enforce this constraint by making all of Fred's constructors private, and
  817. for each constructor have a public (static) create() method which allocates the
  818. Fred object via new and returns a FredPtr (not a Fred*).  That way the only way
  819. anyone could create a Fred object would be to get a FredPtr
  820. ("Fred* p = new Fred()" would be replaced by "FredPtr p = Fred::create()").
  821. Thus no one could accidentally subvert the reference counted mechanism.
  822.  
  823. For example, if Fred had a Fred::Fred() and a Fred::Fred(int i, int j), the
  824. changes to class Fred would be:
  825.  
  826.     class Fred {
  827.     public:
  828.       static FredPtr create()             { return new Fred(); }
  829.       static FredPtr create(int i, int j) { return new Fred(i,j); }
  830.       // ...
  831.     private:
  832.       Fred();
  833.       Fred(int i, int j);
  834.       // ...
  835.     };
  836.  
  837. The end result is that you now have a way to use simple reference counting to
  838. provide "pointer semantics" for a given object.  Users of your Fred class
  839. explicitly use FredPtr objects, which act more or less like Fred* pointers.
  840. The benefit is that users can make as many copies of their FredPtr "smart
  841. pointer" objects, and the pointed-to Fred object will automagically get deleted
  842. when the last such FredPtr object vanishes.
  843.  
  844. If you'd rather give your users "reference semantics" rather than "pointer
  845. semantics," you can use reference counting to provide "copy on write"[16.21].
  846.  
  847. ==============================================================================
  848.  
  849. [16.21] How do I provide reference counting with copy-on-write semantics?
  850.  
  851. The previous FAQ[16.20] a simple reference counting scheme that provided users
  852. with pointer semantics.  This FAQ describes an approach that provides users
  853. with reference semantics.
  854.  
  855. The basic idea is to allow users to think they're copying your Fred objects,
  856. but in reality the underlying implementation doesn't actually do any copying
  857. unless and until some user actually tries to modify the underlying Fred object.
  858.  
  859. Class Fred::Data houses all the data that would normally go into the Fred
  860. class.  Fred::Data also has an extra data member, count_, to manage the
  861. reference counting.  Class Fred ends up being a "smart reference" that
  862. (internally) points to a Fred::Data.
  863.  
  864.     class Fred {
  865.     public:
  866.  
  867.       Fred();                               // A default constructor[10.4]
  868.       Fred(int i, int j);                   // A normal constructor
  869.  
  870.       Fred(const Fred& f);
  871.       Fred& operator= (const Fred& f);
  872.      ~Fred();
  873.  
  874.       void sampleInspectorMethod() const;   // No changes to this object
  875.       void sampleMutatorMethod();           // Change this object
  876.  
  877.       // ...
  878.  
  879.     private:
  880.  
  881.       class Data {
  882.       public:
  883.         Data();
  884.         Data(int i, int j);
  885.         Data(const Data& d);
  886.  
  887.         // Since only Fred can access a Fred::Data object,
  888.         // you can make Fred::Data's data public if you want.
  889.         // But if that makes you uncomfortable, make the data private
  890.         // and make Fred a friend class[14] via friend Fred;
  891.         // ...
  892.  
  893.         unsigned count_;
  894.         // count_ is the number of Fred objects that point at this
  895.         // count_ must be initialized to 1 by all constructors
  896.         // (it starts as 1 since it is pointed to by the Fred object that created it)
  897.       };
  898.  
  899.       Data* data_;
  900.     };
  901.  
  902.     Fred::Data::Data()              : count_(1) /*init other data*/ { }
  903.     Fred::Data::Data(int i, int j)  : count_(1) /*init other data*/ { }
  904.     Fred::Data::Data(const Data& d) : count_(1) /*init other data*/ { }
  905.  
  906.     Fred::Fred()             : data_(new Data()) { }
  907.     Fred::Fred(int i, int j) : data_(new Data(i, j)) { }
  908.  
  909.     Fred::Fred(const Fred& f)
  910.       : data_(f.data_)
  911.     {
  912.       ++ data_->count_;
  913.     }
  914.  
  915.     Fred& Fred::operator= (const Fred& f)
  916.     {
  917.       // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
  918.       // (This order properly handles self-assignment[12.1])
  919.       ++ f.data_->count_;
  920.       if (--data_->count_ == 0) delete data_;
  921.       data_ = f.data_;
  922.       return *this;
  923.     }
  924.  
  925.     Fred::~Fred()
  926.     {
  927.       if (--data_->count_ == 0) delete data_;
  928.     }
  929.  
  930.     void Fred::sampleInspectorMethod() const
  931.     {
  932.       // This method promises ("const") not to change anything in *data_
  933.       // Other than that, any data access would simply use "data_->..."
  934.     }
  935.  
  936.     void Fred::sampleMutatorMethod()
  937.     {
  938.       // This method might need to change things in *data_
  939.       // Thus it first checks if this is the only pointer to *data_
  940.       if (data_->count_ > 1) {
  941.         Data* d = new Data(*data_);    // Invoke Fred::Data's copy ctor
  942.         -- data_->count_;
  943.         data_ = d;
  944.       }
  945.       assert(data_->count_ == 1);
  946.  
  947.       // Now the method proceeds to access "data_->..." as normal
  948.     }
  949.  
  950. If it is fairly common to call Fred's default constructor[10.4], you can avoid
  951. all those new calls by sharing a common Fred::Data object for all Freds that
  952. are constructed via Fred::Fred().  To avoid static initialization order
  953. problems, this shared Fred::Data object is created "on first use" inside a
  954. function.  Here are the changes that would be made to the above code (note that
  955. the shared Fred::Data object's destructor is never invoked; if that is a
  956. problem, either hope you don't have any static initialization order problems,
  957. or drop back to the approach described above):
  958.  
  959.     class Fred {
  960.     public:
  961.       // ...
  962.     private:
  963.       // ...
  964.       static Data* defaultData();
  965.     };
  966.  
  967.     Fred::Fred()
  968.     : data_(defaultData())
  969.     {
  970.       ++ data_->count_;
  971.     }
  972.  
  973.     Fred::Data* Fred::defaultData()
  974.     {
  975.       static Data* p = NULL;
  976.       if (p == NULL) {
  977.         p = new Data();
  978.         ++ p->count_;    // Make sure it never goes to zero
  979.       }
  980.       return p;
  981.     }
  982.  
  983. Note: You can also provide reference counting for a hierarchy of classes[16.22]
  984. if your Fred class would normally have been a base class.
  985.  
  986. ==============================================================================
  987.  
  988. [16.22] How do I provide reference counting with copy-on-write semantics for a
  989.         hierarchy of classes?
  990.  
  991. The previous FAQ[16.21] presented a reference counting scheme that provided
  992. users with reference semantics, but did so for a single class rather than for a
  993. hierarchy of classes.  This FAQ extends the previous technique to allow for a
  994. hierarchy of classes.  The basic difference is that Fred::Data is now the root
  995. of a hierarchy of classes, which probably cause it to have some virtual[20]
  996. functions.  Note that class Fred itself will still not have any virtual
  997. functions.
  998.  
  999. The Virtual Constructor Idiom[20.5] is used to make copies of the Fred::Data
  1000. objects.  To select which derived class to create, the sample code below uses
  1001. the Named Constructor Idiom[10.8], but other techniques are possible (a switch
  1002. statement in the constructor, etc).  The sample code assumes two derived
  1003. classes: Der1 and Der2.  Methods in the derived classes are unaware of the
  1004. reference counting.
  1005.  
  1006.     class Fred {
  1007.     public:
  1008.  
  1009.       static Fred create1(String s, int i);
  1010.       static Fred create2(float x, float y);
  1011.  
  1012.       Fred(const Fred& f);
  1013.       Fred& operator= (const Fred& f);
  1014.      ~Fred();
  1015.  
  1016.       void sampleInspectorMethod() const;   // No changes to this object
  1017.       void sampleMutatorMethod();           // Change this object
  1018.  
  1019.       // ...
  1020.  
  1021.     private:
  1022.  
  1023.       class Data {
  1024.       public:
  1025.         Data() : count_(1) { }
  1026.         Data(const Data& d) : count_(1) { }              // Do NOT copy the 'count_' member!
  1027.         Data& operator= (const Data&) { return *this; }  // Do NOT copy the 'count_' member!
  1028.         virtual ~Data() { assert(count_ == 0); }         // A virtual destructor[20.4]
  1029.         virtual Data* clone() const = 0;                 // A virtual constructor[20.5]
  1030.         virtual void sampleInspectorMethod() const = 0;  // A pure virtual function[22.4]
  1031.         virtual void sampleMutatorMethod() = 0;
  1032.       private:
  1033.         unsigned count_;   // count_ doesn't need to be protected
  1034.         friend Fred;       // Allow Fred to access count_
  1035.       };
  1036.  
  1037.       class Der1 : public Data {
  1038.       public:
  1039.         Der1(String s, int i);
  1040.         virtual void sampleInspectorMethod() const;
  1041.         virtual void sampleMutatorMethod();
  1042.         virtual Data* clone() const;
  1043.         // ...
  1044.       };
  1045.  
  1046.       class Der2 : public Data {
  1047.       public:
  1048.         Der2(float x, float y);
  1049.         virtual void sampleInspectorMethod() const;
  1050.         virtual void sampleMutatorMethod();
  1051.         virtual Data* clone() const;
  1052.         // ...
  1053.       };
  1054.  
  1055.       Fred(Data* data);
  1056.       // Creates a Fred smart-reference that owns *data
  1057.       // It is private to force users to use a createXXX() method
  1058.       // Requirement: data must not be NULL
  1059.  
  1060.       Data* data_;   // Invariant: data_ is never NULL
  1061.     };
  1062.  
  1063.     Fred::Fred(Data* data) : data_(data)  { assert(data != NULL); }
  1064.  
  1065.     Fred Fred::create1(String s, int i)   { return Fred(new Der1(s, i)); }
  1066.     Fred Fred::create2(float x, float y)  { return Fred(new Der2(x, y)); }
  1067.  
  1068.     Fred::Data* Fred::Der1::clone() const { return new Der1(*this); }
  1069.     Fred::Data* Fred::Der2::clone() const { return new Der2(*this); }
  1070.  
  1071.     Fred::Fred(const Fred& f)
  1072.       : data_(f.data_)
  1073.     {
  1074.       ++ data_->count_;
  1075.     }
  1076.  
  1077.     Fred& Fred::operator= (const Fred& f)
  1078.     {
  1079.       // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
  1080.       // (This order properly handles self-assignment[12.1])
  1081.       ++ f.data_->count_;
  1082.       if (--data_->count_ == 0) delete data_;
  1083.       data_ = f.data_;
  1084.       return *this;
  1085.     }
  1086.  
  1087.     Fred::~Fred()
  1088.     {
  1089.       if (--data_->count_ == 0) delete data_;
  1090.     }
  1091.  
  1092.     void Fred::sampleInspectorMethod() const
  1093.     {
  1094.       // This method promises ("const") not to change anything in *data_
  1095.       // Therefore we simply "pass the method through" to *data_:
  1096.       data_->sampleInspectorMethod();
  1097.     }
  1098.  
  1099.     void Fred::sampleMutatorMethod()
  1100.     {
  1101.       // This method might need to change things in *data_
  1102.       // Thus it first checks if this is the only pointer to *data_
  1103.       if (data_->count_ > 1) {
  1104.         Data* d = data_->clone();   // The Virtual Constructor Idiom[20.5]
  1105.         -- data_->count_;
  1106.         data_ = d;
  1107.       }
  1108.       assert(data_->count_ == 1);
  1109.  
  1110.       // Now we "pass the method through" to *data_:
  1111.       data_->sampleInspectorMethod();
  1112.     }
  1113.  
  1114. Naturally the constructors and sampleXXX methods for Fred::Der1 and Fred::Der2
  1115. will need to be implemented in whatever way is appropriate.
  1116.  
  1117. ==============================================================================
  1118.  
  1119. SECTION [17]: Exceptions and error handling
  1120.  
  1121.  
  1122. [17.1] How can I handle a constructor that fails?
  1123.  
  1124. Throw an exception.
  1125.  
  1126. Constructors don't have a return type, so it's not possible to use error codes.
  1127. The best way to signal constructor failure is therefore to throw an exception.
  1128.  
  1129. If you don't have or won't use exceptions, here's a work-around.  If a
  1130. constructor fails, the constructor can put the object into a "zombie" state.
  1131. Do this by setting an internal status bit so the object acts sort of like its
  1132. dead even though it is technically still alive.  Then add a query ("inspector")
  1133. member function to check this "zombie" bit so users of your class can find out
  1134. if their object is truly alive, or if it's a zombie (i.e., a "living dead"
  1135. object).  Also you'll probably want to have your other member functions check
  1136. this zombie bit, and, if the object isn't really alive, do a no-op (or perhaps
  1137. something more obnoxious such as abort()).  This is really ugly, but it's the
  1138. best you can do if you can't (or don't want to) use exceptions.
  1139.  
  1140. ==============================================================================
  1141.  
  1142. [17.2] How should I handle resources if my constructors may throw exceptions?
  1143.  
  1144. Every data member inside your object should clean up its own mess.
  1145.  
  1146. If a constructor throws an exception, the object's destructor is not run.  If
  1147. your object has already done something that needs to be undone (such as
  1148. allocating some memory, opening a file, or locking a semaphore), this "stuff
  1149. that needs to be undone" must be remembered by a data member inside the object.
  1150.  
  1151. For example, rather than allocating memory into a raw Fred* data member, put
  1152. the allocated memory into a "smart pointer" member object, and the destructor
  1153. of this smart pointer will delete the Fred object when the smart pointer dies.
  1154. The standard class auto_ptr is an example of such as "smart pointer" class.
  1155. You can also write your own reference counting smart pointer[16.20].  You can
  1156. also use smart pointers to "point" to disk records or objects on other
  1157. machines[13.3].
  1158.  
  1159. ==============================================================================
  1160.  
  1161. [17.3] How do I change the string-length of an array of char to prevent memory
  1162.        leaks even if/when someone throws an exception?
  1163.  
  1164. If what you really want to do is work with strings, don't use an array of char
  1165. in the first place, since arrays are evil[21.5].  Instead use an object of some
  1166. string-like class.
  1167.  
  1168. For example, suppose you want to get a copy of a string, fiddle with the copy,
  1169. then append another string to the end of the fiddled copy.  The array-of-char
  1170. approach would look something like this:
  1171.  
  1172.     void userCode(const char* s1, const char* s2)
  1173.     {
  1174.       // Get a copy of s1 into a new string called copy:
  1175.       char* copy = new char[strlen(s1) + 1];
  1176.       strcpy(copy, s1);
  1177.  
  1178.       // Now that we have a local pointer to freestore-allocated memory,
  1179.       // we need to use a try block to prevent memory leaks:
  1180.       try {
  1181.  
  1182.         // Now we fiddle with copy for a while...
  1183.         // ...
  1184.  
  1185.         // Later we want to append s2 onto the fiddled-with copy:
  1186.         // ... [Here's where people want to reallocate copy] ...
  1187.         char* copy2 = new char[strlen(copy) + strlen(s2) + 1];
  1188.         strcpy(copy2, copy);
  1189.         strcpy(copy2 + strlen(copy), s2);
  1190.         delete[] copy;
  1191.         copy = copy2;
  1192.  
  1193.         // Finally we fiddle with copy again...
  1194.         // ...
  1195.  
  1196.       } catch (...) {
  1197.         delete[] copy;   // Prevent memory leaks if we got an exception
  1198.         throw;           // Re-throw the current exception
  1199.       }
  1200.  
  1201.       delete[] copy;     // Prevent memory leaks if we did NOT get an exception
  1202.     }
  1203.  
  1204. Using char*s like this is tedious and error prone.  Why not just use an object
  1205. of some string class? Your compiler probably supplies a string-like class, and
  1206. it's probably just as fast and certainly it's a lot simpler and safer than the
  1207. char* code that you would have to write yourself.  For example, if you're using
  1208. the string class from the standardization committee[6.12], your code might look
  1209. something like this:
  1210.  
  1211.     #include <string>           // Let the compiler see class string
  1212.     using namespace std;
  1213.  
  1214.     void userCode(const string& s1, const string& s2)
  1215.     {
  1216.       // Get a copy of s1 into a new string called copy:
  1217.       string copy = s1;         // NOTE: we do NOT need a try block!
  1218.  
  1219.       // Now we fiddle with copy for a while...
  1220.       // ...
  1221.  
  1222.       // Later we want to append s2 onto the fiddled-with copy:
  1223.       copy += s2;               // NOTE: we do NOT need to reallocate memory!
  1224.  
  1225.       // Finally we fiddle with copy again...
  1226.       // ...
  1227.     }                           // NOTE: we do NOT need to delete[] anything!
  1228.  
  1229. ==============================================================================
  1230.  
  1231. -- 
  1232. Marshall Cline / 972-931-9470 / mailto:cline@parashift.com
  1233.