Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!att!dptg!pegasus!hansen From: hansen@pegasus.ATT.COM (Tony L. Hansen) Newsgroups: comp.lang.c++ Subject: Re: delete [] Summary: the differences between delete, delete[] and delete[m] Keywords: arrays, new&delete Message-ID: <4942@pegasus.ATT.COM> Date: 31 Jul 90 15:51:59 GMT References: <641@atcmpe.atcmp.nl> <1990Jul27.231220.8396@cerc.utexas.edu> <4937@pegasus.ATT.COM> Reply-To: hansen@pegasus.ATT.COM (Tony L. Hansen) Organization: AT&T Bell Labs NJ USA Lines: 191 < From: cimshop!davidm@uunet.UU.NET (David S. Masterson) << From: <4937@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) <<< From: lynch@cerc.utexas.edu (Tom Lynch) <<< delete m; would be sufficient. delete [10] m is redundant << Absolutely NOT! Without the [], C++ does not know that it's an array of < Why? I could understand this if m were declared as a pointer and wound up < pointing to an array of 10 somethings, but, if m is declared as an array, < then why doesn't C++ know "that it's an array of objects to be deleted < instead of a single object"? Let's start at the beginning and work forward. "X *x = new X" means to allocate an object of type X, using either operator X::new() or the global operator ::new(), invoke the appropriate constructor for that object, and assign a pointer to it to the pointer x. "X *x = new X[m]" means to allocate an array of objects of type X, using only the global operator ::new(), invoke the appropriate constructor for x[0] through x[m-1], and assign a pointer to the array to the pointer x. The 1990 definition of C++ also mandates that the C++ environment remember the value m associated with that pointer. "delete x" means to take the single object (of type X) that x points to and invoke ~X() followed by either operator X::delete() or the global operator ::delete(). "delete [m] x" means to take the pointer that x points to, treat it as an array, invoke ~X() on x[0] through x[m-1], and then invoke the global operator ::delete(). This syntax is part of all versions of C++ from 1985 through 1990. As of 1990, the syntax is deprecated, meaning that it will go away at some point. "delete [] x" means to take the pointer that x points to, treat it as an array, invoke ~X() on x[0] through x[m-1], where m is the number that was saved away by operator ::new when the array was allocated, and then invoke the global operator ::delete(). This syntax is part of the 1990 definition of C++. Some compilers, in particular AT&T 2.1 cfront, support this syntax. The 2.1 cfront ignores any value passed within the [], just giving a warning message indicating that it is doing so. Note that the compiler is only supposed to look up the number if it is told that the pointer is pointing to an array by using the [] in "delete[] x". It does not look up the number for "delete x". Now consider these two classes: class A { double x; public: A() { x = 3; } double getx() { return x; } void setx(double X) { x = X; } }; class B { double *x; public: B() { x = new double; *x = 3; } ~B() { delete x; } double getx() { return *x; } void setx(double X) { *x = X; } }; These both have a similar interface except that one has a destructor and the other doesn't. Allocate an array of each: A *pa = new A[100]; B *pb = new B[100]; Now let's consider the ramifications of deleting these two arrays using delete [100] pa; or delete [] pa; delete [100] pb; or delete [] pb; and delete pa; delete pb; o delete [100] pa; or delete [] pa; There is no destructor for objects of type A, so the pointer to the memory is passed to the global delete operator, ::delete(). o delete pa; Hmmm, the same thing, the pointer to the memory is passed to ::delete(). Here's a class where it didn't make a difference. o delete [100] pb; or delete [] pb; There is a destructor, so ~B() is called for each of the elements pb[0] through pb[99]. Then the pointer to the memory is passed to ::delete(). o delete pb; Hmmm, there is a destructor, so ~B() is called for *pb. And then the pointer to the memory is passed to ::delete(). But what about pb[1] through pb[99]? They won't be cleaned up at all! Now let's consider adding class-specific memory allocation to A and B. class A { double x; public: A() { x = 3; } double getx() { return x; } void setx(double X) { x = X; } void *operator new(size_t); void operator delete(void*); }; class B { double *x; public: B() { x = new double; *x = 3; } ~B() { delete x; } double getx() { return *x; } void setx(double X) { *x = X; } void *operator new(size_t); void operator delete(void*); }; Note that class-specific allocators are called for allocating single objects of a class. However, arrays of objects are still allocated using the global allocator. Now let's look at calling delete: o delete [100] pa; or delete [] pa; As before, there is no destructor for objects of type A, so the pointer to the memory is passed to the global delete operator, ::delete(). o delete pa; Hmmm, now the pointer to the memory is passed to A::delete() instead of ::delete() even though it was allocated using ::new() instead of A::new(). What happens now is totally unknown. o delete [100] pb; or delete [] pb; As before, there is a destructor, so ~B() is called for each of the elements pb[0] through pb[99]. Then the pointer to the memory is passed to ::delete(). o delete pb; ~B() is called for *pb and then B::delete() is called. As before, ~B() won't be called for pb[1] through pb[99]. That's two strikes against this one! As you can see, the use of "delete x" instead of "delete [] x" is only valid for a vector when the vector that x is pointing to is for a class which does not have a destructor or allocation operators. Given that a class designer should be able to add or delete destructors without affecting the semantics of the program, clearly one should NEVER attempt to delete a vector without the "delete[]" syntax. The ONLY place you're safe in omitting the [] is when deleting a vector of the built in types, such as int's or double's. It's guaranteed that those types will NOT have destructors or allocators. Now let's talk a little bit more about that number which goes within the brackets of "delete[]". It was decided that the programmer has enough to worry about without having to worry about keeping track of the number of elements within the vector. So it was decided that the allocation environment should keep track of the number for you and the number itself was declared redundant. In standards parlance, "the feature was deprecated," that is, the number is allowed but don't expect future versions of the language to permit it. Note that only very recent compilers, such as AT&T's 2.1 cfront, implement this language feature. <<< I don't know what delete [] m means. << As I said, your reference is outdated. The latest C++ rules say that the << number within the [] is unnecessary and the environment is required to << keep track of how many elements are in the array. < Isn't this a contradiction of the previous statement? If the environment < is keeping track of how many elements are in the array, then doesn't it < know that the variable names an array? Perhaps it could, or even should, but the answer is no, the environment is only required to be queried for the size of the array when the objects are deleted via the "delete[]x" syntax, not for the "delete x" syntax. Tony Hansen att!pegasus!hansen, attmail!tony hansen@pegasus.att.com