Berkeley CSUA MOTD:Entry 52093
Berkeley CSUA MOTD
 
WIKI | FAQ | Tech FAQ
http://csua.com/feed/
2025/05/25 [General] UID:1000 Activity:popular
5/25    

2008/11/24-29 [Computer/SW/Languages/C_Cplusplus] UID:52093 Activity:nil
11/23   C++ question: If I have "char *p = new char[10];", is there any real
        difference between "delete p;" and "delete[] p;" after compilation?
        The Standard C free() function only has one form and works for freeing
        both a single character and a character array.  Why are there separate
        forms in C++?  Thx.
        \_ For an array of char, there's no difference.  If you have an array
           of objects, though, delete[] needs to call the destructor for each
           one.  --mconst
        \_ http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
           \_ Thanks to both replies.  -- OP
2025/05/25 [General] UID:1000 Activity:popular
5/25    

You may also be interested in these entries...
2012/7/19-11/7 [Computer/SW/Languages/C_Cplusplus] UID:54439 Activity:nil
7/19    In C or C++, how do I write the code of a function with variable
        number of parameters in order to pass the variable parameters to
        another function that also has variable number of parameters?  Thanks.
        \_ The usual way (works on gcc 3.0+, Visual Studio 2005+):
               #define foo(fmt, ...) printf(fmt, ##__VA_ARGS__)
           The cool new way (works on gcc 4.3+):
	...
2011/3/7-4/20 [Computer/SW/Languages/C_Cplusplus] UID:54056 Activity:nil
3/7     I have a C question.  I have the following source code in two identical
        files t.c and t.cpp:
                #include <stdlib.h>
                int main(int argc, char *argv[]) {
                  const char * const * p1;
                  const char * * p2;
	...
2004/12/14-15 [Computer/SW/Compilers] UID:35291 Activity:moderate
12/14   If I have a C function like this
        void foo(void) {
          static const char unused1[] = "one";
          const char * const unused2 = "two";
          ...... some code ......
          return;
	...
2004/10/29-30 [Computer/SW/Languages/C_Cplusplus] UID:34449 Activity:very high
10/29   C++ is so freaking BROKEN.  Augh!
        \_ Just use C.
           \_ Would if I could.
        \_ No, you are.  C++ works just fine, and far better than C for many
           purposes.
           \_ C vs. C++.  FIGHT!!!
	...
2004/8/10-11 [Computer/SW/Languages/C_Cplusplus, Computer/SW/Compilers] UID:32805 Activity:high
8/10    C question.  Is there anything wrong with the following?
        const my_struct_t **pp;
        pp = malloc(sizeof(my_struct_t *));
        pp = realloc(pp, sizeof (my_struct_t *) * 2);
        "gcc -Wall" doesn't complain.  But the M$ compiler (cl.exe) complains
        about the realloc line:
	...
2004/5/28-29 [Computer/SW/Compilers] UID:30481 Activity:nil
5/28    I just found out that bison inserts these lines of code
                #ifndef __cplusplus
                #ifndef __STDC__
                #define const
                #endif
                #endif
	...
2004/4/13-14 [Computer/SW/Languages/C_Cplusplus] UID:13175 Activity:high
4/13    How much C++/C knowledge do recent Berkeley CS/EECS grad have?
        \_ Class CSGrad inherits FromDaddy and does not implement C++Knowledge
           very well.
           \_ funny.  just the rich and poor as always.  the middle class can't
              afford education.
        \_ They know how to deal with pointers and addresses, malloc and free.
	...
2004/3/30-31 [Computer/SW/Languages/Perl] UID:12925 Activity:kinda low
3/17    In Perl, how do I make variables have static types and type check
        for valid parameter/actuals? I realize that variables are untyped
        in Perl ($var can be 0.001 or "hello") but I'd like to have more
        strict checking so that errors would be caught ahead of run-time,
        Thanks,                                                 -java guy
        \_ use java.  Seriously.  You don't use perl if you want strong
	...
2003/12/8-9 [Computer/SW/Languages/C_Cplusplus] UID:11356 Activity:nil
12/8    c++ question, how do I overload << in my class so it will handle
        endl? ie: myclass << "some string" << endl
        I know how to do the "some string" part:
                myclass & operator << (const char * s);
        what about endl?
        Thanks!!
	...
2003/9/10 [Computer/SW/Languages/C_Cplusplus] UID:29529 Activity:nil
9/10    Stupid question: how do I reference a C callback?
        int mycompare(void const *a, void const *b) { ... }
        qsort(msg, sizeof(Msg), numMsgs, mycompare);
        I get
        "Type error in argument 4 to `qsort'; calling convention mismatch."
        \_ There's nothing wrong in the you reference it.  However, you should
	...
2003/4/22-23 [Computer/SW/Languages/C_Cplusplus] UID:28189 Activity:insanely high
4/22    Anyone know a good link that explains all of C++'s use of the
        keyword mconst?
        \_ http://www.parashift.com/c++-faq-lite
           Search for const in the text box.
           Search for mconst in the text box.
           \- perfection
	...
Cache (8192 bytes)
www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
Does delete p delete the pointer p, or the pointed-to-data *p? The keyword should really be delete_the_thing_pointed_to_by. The same abuse of English occurs when freeing the memory pointed to by a pointer in C: free really means free_the_stuff_pointed_to_by. It might, depending on the phase of the moon, corrupt your heap, crash your program, make arbitrary and bizarre changes to objects that are already out there on the heap, etc. Unfortunately these symptoms can appear and disappear randomly. Note: some runtime systems will protect you from certain very simple cases of double delete. So back to Murphy: since it can go wrong, it will, and it will go wrong at the worst possible moment. Do NOT email me saying you tested it and it doesn't crash. It is perfectly legal, moral, and wholesome to use malloc() and delete in the same program, or to use new and free() in the same program. But it is illegal, immoral, and despicable to call free() with a pointer allocated via new, or to call delete on a pointer allocated via malloc(). I occasionally get e-mail from people telling me that it works OK for them on machine X and compiler Y Just because they don't see bad symptoms in a simple test case doesn't mean it won't crash in the field. Even if they know it won't crash on their particular compiler doesn't mean it will work safely on another compiler, another platform, or even another version of the same compiler. Sometimes people say, "But I'm just working with an array of char." Nonetheless do not mix malloc() and delete on the same pointer, or new and free() on the same pointer! Mixing these up could cause a catastrophic failure at runtime if the code was ported to a new machine, a new compiler, or even a new version of the same compiler. When realloc() has to copy the allocation, it uses a bitwise copy operation, which will tear many C++ objects to shreds. They use their own copy constructor or assignment operator. Besides all that, the heap that new uses may not be the same as the heap that malloc() and realloc() use! exceptions, your code might be even more tedious: Fred* p = new Fred(); if (p == NULL) { std::cerr << "Couldn't allocate memory for a Fred" << std::endl; In C++, if the runtime system cannot allocate sizeof(Fred) bytes of memory during p = new Fred(), a std::bad_alloc exception will be thrown. Therefore you should simply write: Fred* p = new Fred(); Find out by checking your compiler's documentation under "new". the NULL test, you can force the runtime system to do the test by installing a "new handler" function. Your "new handler" function can do anything you want, such as throw an exception, delete some objects and return (in which case operator new will retry the allocation), print a message and abort() the program, etc. Here's a sample "new handler" that prints a message and throws an exception. The handler is installed using std::set_new_handler(): #include <new> // To get std::set_new_handler #include <cstdlib> // To get abort() #include <iostream> // To get std::cerr class alloc_error : public std::exception { public: alloc_error() : exception() { } }; This means that new will never return NULL: Fred* p = new Fred(); Unfortunately there's no convenient way to guarantee that the std::set_new_handler() will be called before the first use of new. For example, even if you put the std::set_new_handler() call in the constructor of a global object, you still don't know if the module ("compilation unit") that contains that global object will be elaborated first or last or somewhere inbetween. Therefore you still don't have any guarantee that your call of std::set_new_handler() will happen before any other global's constructor gets invoked. The C++ language guarantees that delete p will do nothing if p is equal to NULL. Since you might get the test backwards, and since most testing methodologies force you to explicitly test every branch point, you should not put in the redundant if test. delete p is a two-step process: it calls the destructor, then releases the memory. The code generated for delete p is functionally similar to this (assuming p is of type Fred*): // Original code: delete p; In p = new Fred(), does the Fred memory "leak" if the Fred constructor throws an exception? If an exception occurs during the Fred constructor of p = new Fred(), the C++ language guarantees that the memory sizeof(Fred) bytes that were allocated will automagically be released back to the heap. Here are the details: new Fred() is a two-step process: 1 sizeof(Fred) bytes of memory are allocated using the primitive void* operator new(size_t nbytes). This primitive is similar in spirit to malloc(size_t nbytes). The pointer returned from the first step is passed as the this parameter to the constructor. catch block to handle the case when an exception is thrown during this step. Thus the actual generated code is functionally similar to: // Original code: Fred* p = new Fred(); This syntax is necessary because there is no syntactic difference between a pointer to a thing and a pointer to an array of things (something we inherited from C). Long answer: The run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the pointer, p There are two popular techniques that do this. Both these techniques are in use by commercial-grade compilers, both have tradeoffs, and neither is perfect. placement new, nor a local object on the stack, nor a global, nor a member of another object; In other words, you must not examine it, compare it with another pointer, compare it with NULL, print it, cast it, do anything with it. the rectangular matrix code from the previous FAQ: // The code for class Matrix is shown below... void manipulateArray(unsigned nrows, unsigned ncols) { Matrix matrix(nrows, ncols); For example, there aren't any delete statements in the above code, yet there will be no memory leaks, assuming only that the Matrix destructor does its job correctly. Here's the Matrix code that makes the above possible: class Matrix { public: Matrix(unsigned nrows, unsigned ncols); h" // To get the definition for class Fred // The code for Matrix<T> is shown below... void manipulateArray(unsigned nrows, unsigned ncols) { Matrix<Fred> matrix(nrows, ncols); For example, the following uses a Matrix of std::string (where std::string is the standard string class): #include <string> void someFunction(std::string& s); void manipulateArray(unsigned nrows, unsigned ncols) { Matrix<std::string> matrix(nrows, ncols); the standard library has a std::vector template that provides this behavior. No, in the sense that built-in array types need to have their length specified at compile time. Yes, in the sense that even built-in array types can specify the first index bounds at run-time. Eg, comparing with the previous FAQ, if you only need the first array dimension to vary then you can just ask new for an array of arrays, rather than an array of pointers to arrays: const unsigned ncols = 100; As usual with the Named Constructor Idiom, the constructors are all private or protected, and there are one or more public static create() methods (the so-called "named constructors"), one per constructor. In this case the create() methods allocate the objects via new. Since the constructors themselves are not public, there is no other way to create objects of the class. class Fred { public: // The create() methods are the "named constructors": static Fred* create() { return new Fred(); private: // The constructors themselves are private or protected: Fred(); friend of Fred if you want to allow a Wilma to have a member object of class Fred, but of course this is a softening of the original goal, namely to force Fred objects to be allocated via new. self-assignment) // (This order also properly handles recursion, eg, if a Fred contains FredPtrs) Fred* const old = p_; Note that you can soften the "never NULL" rule above with a little more checking in the constructor, copy constructor, assignment operator, and destructor. I would recommend against an operator Fred*() method, since that would let people accidentally get at the Fred*. One of the implicit const...