leo@atcmp.nl (Leo Willems) (07/27/90)
When shifting from 2.0 to 2.1 I found myself in problems with:
func(){
classtype *m = new classtype[10];
delete[10] m;
}
In 2.0 this works fine, in 2.1 not, that compilers suggests:
delete [] m;
which indeed works correct. (but not in 2.0, which accepts the code but
generates a .c file with a syntax error)
Is delete[] indeed the correct way ?
Should delete[] be accepted by 2.0 or is it new to 2.1?
Thanks in advance, Leo
Leo Willems Internet: leo@atcmp.nl
AT Computing UUCP: mcsun!hp4nl!kunivv1!atcmpe!leo
P. O. Box 1428
6501 BK Nijmegen Phone: +31-80-566880
The Netherlands Fax: +31-80-555887
lynch@cerc.utexas.edu (Tom Lynch) (07/28/90)
In article <641@atcmpe.atcmp.nl> leo@atcmp.nl (Leo Willems) writes: >When shifting from 2.0 to 2.1 I found myself in problems with: > >func(){ > classtype *m = new classtype[10]; > > delete[10] m; >} > >In 2.0 this works fine, in 2.1 not, that compilers suggests: > > delete [] m; > >which indeed works correct. (but not in 2.0, which accepts the code but >generates a .c file with a syntax error) > >Is delete[] indeed the correct way ? >Should delete[] be accepted by 2.0 or is it new to 2.1? delete m; would be sufficient. delete [10] m is redundant Stroustrup p 259: "In the form delete [ expression ] expression the second expression points to a vector and first expression gives the number of elements of that vector. Specifying the number of elements is redundant except when deleting vectors of certain classes..." I don't know what delete [] m means. -tom lynch@cerc.utexas.edu Nothing is absolute. p.s. please send me a note if this posted. Does anyone use the 'F' in rn? should it work?
rfg@NCD.COM (Ron Guilmette) (07/29/90)
In article <641@atcmpe.atcmp.nl> leo@atcmp.nl (Leo Willems) writes: >When shifting from 2.0 to 2.1 I found myself in problems with: > >func(){ > classtype *m = new classtype[10]; > > delete[10] m; >} > >In 2.0 this works fine, in 2.1 not, that compilers suggests: > > delete [] m; > >which indeed works correct. (but not in 2.0, which accepts the code but >generates a .c file with a syntax error) > >Is delete[] indeed the correct way ? This is a relative recent change in the definition of the language, and in the cfront implementation of the language. Thus, it is not surprizing that it has thrown some people for a loop. The new Annotated C++ Reference Manual (E&S) clearly indicates that the proper way to delete an array of things which are pointed to by some pointer `p' is to say: delete [] p; In the old days (e.g. when using 2.0 and earlier) you needed to write the actual number of elements inside the [], but that's not needed anymore, nor will it be in the future. >Should delete[] be accepted by 2.0 or is it new to 2.1? This is new in 2.1. You will not be able to use this simpler notation/syntax if you are still working with cfront 2.0 (or earlier). P.S. For anybody out there who is doing serious work with C++ and who has not yet obtained a copy of the new Annotated C++ Reference Manual, I have only two words for you. Get it. 'nuff said. -- // Ron Guilmette // C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
hansen@pegasus.ATT.COM (Tony L. Hansen) (07/29/90)
< 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 objects to be deleted instead of a single object, and the destructors would not be called for elements 1..m of the array. < Stroustrup p 259: Your reference is outdated. Get Stroustrup's latest work, coauthored with Margaret Ellis, The Annotated C++ Reference Manual, a.k.a. E&S. < 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. Tony Hansen att!pegasus!hansen, attmail!tony hansen@pegasus.att.com
davidm@uunet.UU.NET (David S. Masterson) (07/31/90)
In article <4937@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: < 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 objects to be deleted instead of a single object, and the destructors would not be called for elements 1..m of the array. 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"? < 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? -- =================================================================== David Masterson Consilium, Inc. uunet!cimshop!davidm Mt. View, CA 94043 =================================================================== "If someone thinks they know what I said, then I didn't say it!"
hansen@pegasus.ATT.COM (Tony L. Hansen) (07/31/90)
< 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
ssr@taylor.Princeton.EDU (Steve S. Roy) (08/01/90)
In article <4942@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: > > "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. > Sorry, but I don't have docs for 2.1 available. Is there any way for me to get at the size of that array without remembering it thru my code? That way I could, say, iterate over all elements of the array without having a stupid variable like n_x around. Steve
hansen@pegasus.ATT.COM (Tony L. Hansen) (08/03/90)
< From: ssr@taylor.Princeton.EDU (Steve S. Roy)
< In article <4942@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes:
<< "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.
<
< Sorry, but I don't have docs for 2.1 available. Is there any way for me
< to get at the size of that array without remembering it thru my code?
< That way I could, say, iterate over all elements of the array without
< having a stupid variable like n_x around.
I don't believe that there's such a requirement at this time. An
implementation is free to provide a method of accessing that number, but I
don't think that 2.1 does. Sorry.
You can always propose such a requirement within comp.std.c++.
Tony Hansen
att!pegasus!hansen, attmail!tony
hansen@pegasus.att.com
davidm@uunet.UU.NET (David S. Masterson) (08/03/90)
Whoa! What a reply (certainly made things a lot more clearer for me). Of course, my question was not meant to argue language definition (you're far more versed in it than I ;-). On the contrary, my question was more of a should it be this way. I think you got both sides of it, though, which was good. :-) However, I have a few more questions... In article <4942@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: >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. Hmmmm. If someone had developed X for an embedded system such that X.new() allocates space for X in a special memory area, then X could never "validly" be used in an array form because "new X[m]" would cause it to be allocated in standard memory. Does anyone see a problem with this? > "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". Here too, if X only points to special memory, then everything is fine, but if X was supposed to totally reside in a special area, then X could not be allocated as an array. Does anyone see a problem with this? In both cases, it may be a non-problem. I guess its just a quirk of the language and people program around it by never writing their classes such that they are supposed to wholly reside in special areas but rather point to pieces that are special. Programmers may even be doing this without realizing the other side of the coin (thus its a non-problem). By the way, it is true that the delete() operator (global or class specific) is called automatically after the destructor, right? (I'm still working with a V1.2 compiler) By this, I mean that there isn't a need to have the destructor call delete()? (Your later example confused me slightly on this.) ><<< 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. Is this "size of the array" in the compiler's environment (in other words, determined at compile time) or in the run-time environment (in other words, somehow tacked onto the memory that is allocated)? There must be plusses and minusses with either way. -- =================================================================== David Masterson Consilium, Inc. uunet!cimshop!davidm Mt. View, CA 94043 =================================================================== "If someone thinks they know what I said, then I didn't say it!"
hansen@pegasus.ATT.COM (Tony L. Hansen) (08/05/90)
< From: cimshop!davidm@uunet.UU.NET (David S. Masterson) < Hmmmm. If someone had developed X for an embedded system such that < X.new() allocates space for X in a special memory area, then X could never < "validly" be used in an array form because "new X[m]" would cause it to be < allocated in standard memory. Does anyone see a problem with this? < < Here too, if X only points to special memory, then everything is fine, but < if X was supposed to totally reside in a special area, then X could not be < allocated as an array. Does anyone see a problem with this? If you're developing such a class, then you do indeed have to be aware of the ins and outs of arrays. Be careful when you play around with "special memory segments"! < By the way, it is true that the delete() operator (global or class < specific) is called automatically after the destructor, right? (I'm still < working with a V1.2 compiler) By this, I mean that there isn't a need to < have the destructor call delete()? (Your later example confused me < slightly on this.) Sorry, I didn't mean to cause confusion. :-) You're correct: one of operator X::delete() or ::delete() IS called automatically after the destructor (~X()) when the variable is passed to the delete operator. Just to throw in another monkey wrench, it is possible to explicitly call X::~X() for an allocated variable; this is sometimes necessary when dealing with those "special memory segments" mentioned above. (This feature was introduced in the 1989 definition of the language, a.k.a. 2.0.) < Is this "size of the array" in the compiler's environment (in other words, < determined at compile time) or in the run-time environment (in other < words, somehow tacked onto the memory that is allocated)? There must be < plusses and minusses with either way. It's "typically" implemented using a run time tracking. (How do you define "typical" when very few compilers implement the feature? :-) ) I suppose it WOULD be possible for an implementation to keep track at compile time for SOME arrays, but that would be a matter of "quality of implementation" and is not a language issue. Tony Hansen att!pegasus!hansen, attmail!tony hansen@pegasus.att.com
kearns@cs.columbia.edu (Steve Kearns) (08/06/90)
Re the conflict between "delete [] foo" and "delete foo": The "right" way, of course, is for C++ to support the "Array of" type constructor. While this would require updating lots of existing code (mainly, changing "fooType * f" to "fooType[] * f"), it would eliminate a problem with C: the double role of pointers to objects and pointers to arrays of objects. Of course, any change that requires updating lots of code is unacceptable; but I for one am looking forward to the day when D++ is available, and we can shed all of these C bletcherisms and C++ complexities. -steve
davidm@uunet.UU.NET (David S. Masterson) (08/07/90)
In article <4956@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: < From: cimshop!davidm@uunet.UU.NET (David S. Masterson) < Hmmmm. If someone had developed X for an embedded system such that < X.new() allocates space for X in a special memory area, then X could never < "validly" be used in an array form because "new X[m]" would cause it to be < allocated in standard memory. Does anyone see a problem with this? If you're developing such a class, then you do indeed have to be aware of the ins and outs of arrays. Be careful when you play around with "special memory segments"! You didn't answer the question !-) Perhaps you missed the point of the question (nah! ;-). Obviously, by the current definition of the language, there are some gotchas with the scenario above, but the question is should those gotchas exist? Why? Just to throw in another monkey wrench, it is possible to explicitly call X::~X() for an allocated variable; this is sometimes necessary when dealing with those "special memory segments" mentioned above. (This feature was introduced in the 1989 definition of the language, a.k.a. 2.0.) Is this a trick to deal with the above? Should a language consider a special trick for not too-special cases a language "feature"? Wait a sec (looking at above a little more cross-eyed), how would the explicit call to X::~X() work for this case?? < There must be plusses and minusses with either way. < [of tracking array sizes] I suppose it WOULD be possible for an implementation to keep track at compile time for SOME arrays, but that would be a matter of "quality of implementation" and is not a language issue. Why SOME arrays? The information is there at compile time for all arrays, isn't it? (NOTE: I didn't say pointers to arrays.) I think the "quality" belongs more in the definition of the language than the implementation. -- =================================================================== David Masterson Consilium, Inc. uunet!cimshop!davidm Mt. View, CA 94043 =================================================================== "If someone thinks they know what I said, then I didn't say it!"
hansen@pegasus.ATT.COM (Tony L. Hansen) (08/07/90)
<From: cimshop!davidm@uunet.UU.NET (David S. Masterson)
<<In article <4956@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen)
writes:
<<< From: cimshop!davidm@uunet.UU.NET (David S. Masterson) Hmmmm. If
<<< someone had developed X for an embedded system such that X.new()
<<< allocates space for X in a special memory area, then X could never
<<< "validly" be used in an array form because "new X[m]" would cause it to
<<< be allocated in standard memory. Does anyone see a problem with this?
<<
<< If you're developing such a class, then you do indeed have to be aware of
<< the ins and outs of arrays. Be careful when you play around with "special
<< memory segments"!
<
< You didn't answer the question !-) Perhaps you missed the point of the
< question (nah! ;-). Obviously, by the current definition of the language,
< there are some gotchas with the scenario above, but the question is should
< those gotchas exist? Why?
There really are two ways of looking at the original question above: from
the point of view of someone who wishes to use a particular language feature
and needs to know the ins and outs for doing so, and from the point of view
of someone who wishes to pick on the language itself. Since this discussion
started out in the context of the first set of people, my response above was
aimed at that set.
YES, it is reasonable to consider enhancements to the current definition
such that allocation of arrays could be better managed for use in "special
memory segments". Start up a discussion in comp.std.c++ if you wish to
discuss such extensions.
<< Just to throw in another monkey wrench, it is possible to explicitly call
<< X::~X() for an allocated variable; this is sometimes necessary when
<< dealing with those "special memory segments" mentioned above. (This
<< feature was introduced in the 1989 definition of the language, a.k.a.
<< 2.0.)
<
< Is this a trick to deal with the above? Should a language consider a
< special trick for not too-special cases a language "feature"? Wait a sec
< (looking at above a little more cross-eyed), how would the explicit call
< to X::~X() work for this case??
The availability of X::~X() permits a function to destruct an object without
it invoking X::delete() or ::delete(). This is particularly useful for a
class whose objects have been allocated using "alternate" allocation
schemes, such as when using X::new() with extra arguments.
<<< There must be plusses and minusses with either way.
<<< [of tracking array sizes]
<< I suppose it
<< WOULD be possible for an implementation to keep track at compile time for
<< SOME arrays, but that would be a matter of "quality of implementation" and
<< is not a language issue.
<
< Why SOME arrays? The information is there at compile time for all arrays,
< isn't it? (NOTE: I didn't say pointers to arrays.) I think the "quality"
< belongs more in the definition of the language than the implementation.
No, the information is NOT there at compile time for all arrays that get
passed to ::delete(). When you use ::new() to allocate an array, you get a
pointer back. If you pass that pointer on to another function which winds up
doing the delete[], HOW is that function going to know the number of
elements to delete? For this case you HAVE to have run time information.
Whether that size information is passed via a tagged pointer, or the size
info is kept in a separate table, or the size info is kept in the heap arena
next to the object itself, or wherever, the info can only be accessed at run
time in order to delete the array.
Tony Hansen
att!pegasus!hansen, attmail!tony
hansen@pegasus.att.com