Why does delete[] exist?

282 views
Skip to first unread message

Apurva Mehta

unread,
Sep 15, 2002, 12:15:59 PM9/15/02
to
I have been wondering why the special destruction operator for arrays,
delete[], exists for C++. I know that it is used to destroy dynamically
allocated arrays which are created using new[], but why not have just one
version of delete which determines on its own whether the object it is
destroying is an array of objects or an individual.

One argument is that having 2 versions of delete boosts efficiency. To
quote Bjarne Stroustrup:

"The special destruction operator for arrays, delete[], isn't logically
necessary. However, suppose the implementation of the free store had been
required to hold sufficient information for every object to tell if it was
an individual or an array. The user would have been relieved of the
burden, but that obligation would have imposed significant time and space
overheads on some C++ implementations." (from The C++ Progarmming
Language, Special Edition, Pg 251).

If so, then why don't we do "delete[100] foo"?

I am sure there is a good reason behind this, but I have not
found it, nor can I think of one. Any ideas would be appreciated.

Thanks for your time.

-=-=-=-=-=-
My real email address does not contain spam spelt backwards.
-=-=-=-=-=-

Victor Bazarov

unread,
Sep 15, 2002, 1:22:26 PM9/15/02
to
"Apurva Mehta" <apu...@maps.gmx.net> wrote...

> I have been wondering why the special destruction operator for arrays,
> delete[], exists for C++. I know that it is used to destroy dynamically
> allocated arrays which are created using new[], but why not have just one
> version of delete which determines on its own whether the object it is
> destroying is an array of objects or an individual.
>
> One argument is that having 2 versions of delete boosts efficiency. To
> quote Bjarne Stroustrup:
>
> "The special destruction operator for arrays, delete[], isn't logically
> necessary. However, suppose the implementation of the free store had been
> required to hold sufficient information for every object to tell if it was
> an individual or an array. The user would have been relieved of the
> burden, but that obligation would have imposed significant time and space
> overheads on some C++ implementations." (from The C++ Progarmming
> Language, Special Edition, Pg 251).
>
> If so, then why don't we do "delete[100] foo"?

Because it is not practical to require the programmer to keep
the sizes of arrays around: allocation and deallocation often
happens in different modules and the calculation of the size
during allocation may not be repeatable. Of course, as a result
we have a recurring question: why isn't there a way to know the
size of a dynamic array since the implementation knows it anyway.
Something like sizeof[](ptr_to_dynamically_allocated_array)...

Well, there are certainly interesting inconsistencies in the
language...

> I am sure there is a good reason behind this, but I have not
> found it, nor can I think of one. Any ideas would be appreciated.

Post to comp.std.c++. They hold the answers to "why it is so
in the Standard" (compared to this NG, where we mostly concern
ourselves with "how to do it according to the Standard").

Victor
--
Please remove capital A's from my address when replying by mail


Siemel Naran

unread,
Sep 16, 2002, 3:05:37 AM9/16/02
to
"Apurva Mehta" <apu...@maps.gmx.net> wrote in message news:am2ao1

> One argument is that having 2 versions of delete boosts efficiency. To
> quote Bjarne Stroustrup:
>
> "The special destruction operator for arrays, delete[], isn't logically
> necessary. However, suppose the implementation of the free store had been
> required to hold sufficient information for every object to tell if it was
> an individual or an array. The user would have been relieved of the
> burden, but that obligation would have imposed significant time and space
> overheads on some C++ implementations." (from The C++ Progarmming
> Language, Special Edition, Pg 251).

I don't buy the "significant". It seems like an exaggeration.


> If so, then why don't we do "delete[100] foo"?
>
> I am sure there is a good reason behind this, but I have not
> found it, nor can I think of one. Any ideas would be appreciated.

I don't think there is a good reason.

--
+++++++++++
Siemel Naran


Apurva Mehta

unread,
Sep 16, 2002, 8:25:48 AM9/16/02
to
>"Victor Bazarov" <vAba...@dAnai.com> wrote in message >news:<uo9gefm...@corp.supernews.com>...

> Because it is not practical to require the programmer to keep
> the sizes of arrays around: allocation and deallocation often
> happens in different modules and the calculation of the size
> during allocation may not be repeatable. Of course, as a result
> we have a recurring question: why isn't there a way to know the
> size of a dynamic array since the implementation knows it anyway.
> Something like sizeof[](ptr_to_dynamically_allocated_array)...
>
> Well, there are certainly interesting inconsistencies in the
> language...

Another question that can be asked is that if the implementation knows
the size of a dynamic array then how is there a "significant" time and
space overhead if only one version of delete is used? From my point of
view, only one additional check would be required at the time of
destruction/deletion and even that can be avoided.

> Post to comp.std.c++. They hold the answers to "why it is so
> in the Standard" (compared to this NG, where we mostly concern
> ourselves with "how to do it according to the Standard").
>
> Victor

I have already posted on that NG. However, I thought I would reply
here as well.

Apurva

Carsten Olsen

unread,
Sep 16, 2002, 8:44:05 AM9/16/02
to
"Apurva Mehta" <apu...@maps.gmx.net> wrote in message
news:am2ao1$nja$1...@news.vsnl.net.in...

>
> I am sure there is a good reason behind this, but I have not
> found it, nor can I think of one. Any ideas would be appreciated.
>

I checked the C++-faq some time ago for the same subject. There is some good
information
in the following link
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.10

Regards

Carsten Olsen

Karl Heinz Buchegger

unread,
Sep 16, 2002, 8:55:14 AM9/16/02
to

The OP's question was more of the sort: Why are things the way they are in C++?

Indeed as I see it, there is no good reason to have the distinction between
delete and delete[]. The functionality of both could have been integrated
into a single delete, since in case of an array the run time system already
needs to store the number of objects for each allocation somewhere in order
to call the correct number of destructors.

--
Karl Heinz Buchegger
kbuc...@gascad.at

Michael Kochetkov

unread,
Sep 16, 2002, 9:08:50 AM9/16/02
to

"Karl Heinz Buchegger" <kbuc...@gascad.at> wrote in message
news:3D85D4B2...@gascad.at...
[...]

> Indeed as I see it, there is no good reason to have the distinction
between
> delete and delete[]. The functionality of both could have been integrated
> into a single delete, since in case of an array the run time system
already
> needs to store the number of objects for each allocation somewhere in
order
> to call the correct number of destructors.
Agreed. That is the way the early Borland's compilers worked.

--
With regards,
Michael Kochetkov.


tom_usenet

unread,
Sep 16, 2002, 10:44:14 AM9/16/02
to

But the point is that it doesn't have to store that number if you
haven't got an array.

Imagine allocating a linked list where every single node in the linked
list has an extra 4 bytes allocated to hold the fact the the node,
unsurprisingly, has 1 node object in it. This could double the memory
required by a singly linked list.

struct Node
{
int val;
Node* next;
};

This might be 8 bytes.

But, say you need an extra 4 bytes for the compiler to hold the fact
that you *don't* have an array of nodes. Suddenly

Node* n = new Node;

requires 12 bytes, which probably works out as 16 bytes after
alignment has been fixed.

Anyway, I certainly don't want to have to pay that kind of overhead
just so I don't have to remember to write delete[]. Some compilers
build in the overhead anyway, but some don't.

Tom

Karl Heinz Buchegger

unread,
Sep 16, 2002, 11:19:52 AM9/16/02
to

tom_usenet wrote:
>
>
> But the point is that it doesn't have to store that number if you
> haven't got an array.

If you are not programming on an embedded chip, this is hardly an argument
in this days.
"... but that obligation would have imposed significant time and space
overheads ..."

I wouldn't call it significant. Overhead, yes. But significant?

>
> Imagine allocating a linked list where every single node in the linked
> list has an extra 4 bytes allocated to hold the fact the the node,
> unsurprisingly, has 1 node object in it. This could double the memory
> required by a singly linked list.
>
> struct Node
> {
> int val;
> Node* next;
> };
>
> This might be 8 bytes.
>
> But, say you need an extra 4 bytes for the compiler to hold the fact
> that you *don't* have an array of nodes. Suddenly
>
> Node* n = new Node;
>
> requires 12 bytes, which probably works out as 16 bytes after
> alignment has been fixed.

True, but ... have you ever seen such a node in production coding?
I haven't. All node structures ever used in linked list were definitly
larger :-)

>
> Anyway, I certainly don't want to have to pay that kind of overhead
> just so I don't have to remember to write delete[].

Well. I would be willing to pay that price.

Alexander Terekhov

unread,
Sep 16, 2002, 11:27:33 AM9/16/02
to

Apurva Mehta wrote:
>
> I have been wondering why the special destruction operator for arrays,
> delete[], exists for C++. I know that it is used to destroy dynamically
> allocated arrays which are created using new[], but why not have just one
> version of delete which determines on its own whether the object it is
> destroying is an array of objects or an individual.
>
> One argument is that having 2 versions of delete boosts efficiency. To
> quote Bjarne Stroustrup:
>
> "The special destruction operator for arrays, delete[], isn't logically
> necessary. However, suppose the implementation of the free store had been
> required to hold sufficient information for every object to tell if it was
> an individual or an array. The user would have been relieved of the
> burden, but that obligation would have imposed significant time and space
> overheads on some C++ implementations." (from The C++ Progarmming
> Language, Special Edition, Pg 251).
>
> If so, then why don't we do "delete[100] foo"?

Uhmm, do you really want to be REQUIRED to do delete[100] array_
of_chars_or_whatever_with_TRIVIAL_dtors_foo? What should some
"silly implementation" [using e.g. std::free() for its void
operator delete[](void*)throw()] do with the number of elements
and/or array size, in THIS case [and without some sophisticated
user-defined void operator delete[]( void*,size_t ) throw()]?
Do you really want to have "delete" distinction for arrays with
trivial dtors vs. arrays with nontrivial dtors (w.r.t. array
elements, I mean)? What about all those fancy templates (oh,
yeah, they should use std::vector/deque, sure ;-) )?

Well, of course, you COULD {kinda} do "delete[100] foo", I guess:

array< Foo,100 >* foo = new array< Foo,100 >;
delete foo;

and, BTW, you COULD also do this:

array< Foo,100 >* foo = new array< Foo,100 >[1];
delete[] foo; // let's forget non-[] new for "single" objects
// and ALWAYS use rather smart delete[]!!! ;-)
// ("delete this;" and etc. "silly" stuff aside)

regards,
alexander.

Karl Heinz Buchegger

unread,
Sep 16, 2002, 11:36:54 AM9/16/02
to

Alexander Terekhov wrote:
>
> >
> > If so, then why don't we do "delete[100] foo"?
>
> Uhmm, do you really want to be REQUIRED to do delete[100] array_
> of_chars_or_whatever_with_TRIVIAL_dtors_foo?

That was not the point Apurva was trying to make.

The point was:
if we have that distinction between
delete and delete[]
then the programmer has to remember that the thing he needs
to delete is an array. Obviously somewhere it has to be stored
how big that array has been allocated otherwise delete[] would
not work.
But if this is so, then why is the programmer required to remember
that the whole thing is an array in the first place? Why not go
one step further and free the programmer from that burden too?

Alexander Terekhov

unread,
Sep 16, 2002, 11:55:28 AM9/16/02
to

Karl Heinz Buchegger wrote:
[...]

> if we have that distinction between
> delete and delete[]
> then the programmer has to remember that the thing he needs
> to delete is an array. Obviously somewhere it has to be stored
> how big that array has been allocated otherwise delete[] would
> not work.

That's NOT always true.

> But if this is so, then why is the programmer required to remember
> that the whole thing is an array in the first place? Why not go
> one step further and free the programmer from that burden too?

Feel free to: pSingle = new Whatever[1]; /*...*/ delete[] pSingle;

regards,
alexander.

Victor Bazarov

unread,
Sep 16, 2002, 1:00:47 PM9/16/02
to
"Karl Heinz Buchegger" <kbuc...@gascad.at> wrote...


Actually, IIRC, there either was or is a compiler that offers
(or offered) that as an extension...

Here is my question: according to the Standard, you are supposed
to delete[] even if you did "new blah[1]" (which supposedly has
the same effect as "new blah"). Can we do a plain "delete" on
a pointer to an array of one? Another facet of the same question:
if I allocate one object using "new blah" (not an array), I must
be able to say ptr[0] (because it's the same as *ptr), but may I
use ptr + 1 as the "one past the end of the 'array'" or would it
be an error (since it wasn't an array to begin with)?

I guess those are questions for comp.std.c++...

Andrey Tarasevich

unread,
Sep 16, 2002, 2:27:17 PM9/16/02
to
Victor Bazarov wrote:
> ...
> Here is my question: according to the Standard, you are supposed
> to delete[] even if you did "new blah[1]" (which supposedly has
> the same effect as "new blah"). Can we do a plain "delete" on
> a pointer to an array of one?

No. In order to deallocate an object of array type one should always use
'delete[]', not 'delete'. Even though it has only one element, it is still
an object of array type.

> Another facet of the same question:
> if I allocate one object using "new blah" (not an array), I must
> be able to say ptr[0] (because it's the same as *ptr), but may I
> use ptr + 1 as the "one past the end of the 'array'" or would it
> be an error (since it wasn't an array to begin with)?

> ...

Yes, you may. The standard specifically says so in 5.7/4.

--
Best regards,
Andrey Tarasevich
Brainbench C and C++ Programming MVP

-----------== Posted via Newsfeed.Com - Uncensored Usenet News ==----------
http://www.newsfeed.com The #1 Newsgroup Service in the World!
-----= Over 100,000 Newsgroups - Unlimited Fast Downloads - 19 Servers =-----

NotFound

unread,
Sep 16, 2002, 1:43:40 PM9/16/02
to
Karl Heinz Buchegger escribió:

> Well. I would be willing to pay that price.

Then you can use always delete [], simply use always new x [1]; in lieu
of new x;

Regards.

Alexander Terekhov

unread,
Sep 16, 2002, 3:00:23 PM9/16/02
to

Victor Bazarov wrote:
[...]

> Here is my question: according to the Standard, you are supposed
> to delete[] even if you did "new blah[1]" (which supposedly has
> the same effect as "new blah").

It "has the same effect as" calling 'proper' operator new[], object
construction, and ensuring that after {nontrivial} destruction the
same pointer will be passed to operator delete[] (without or with
size_t arg; and size should then match allocation request as well;
BTW, MS-VC7 is {still} buggy here (N>1), AFAICT).

<d.cpp>

#include <iostream>
using namespace std;

template< class T, unsigned N >
struct array { T t[N];
void* operator new( size_t n ) { void* p = ::operator new(n); cout << "\t\t\tARRAY NEW: " << n << " " << p << endl; return p; }
void* operator new[]( size_t n ) { void* p = ::operator new(n); cout << "\t\t\tARRAY NEW[]: " << n << " " << p << endl; return p; }
void operator delete[]( void* p,size_t n ) { cout << "\t\t\tARRAY DELETE[]: " << p << " " << n << endl << endl;}
void operator delete( void* p,size_t n ) { cout << "\t\t\tARRAY DELETE: " << p << " " << n << endl << endl;}
};

struct Foo { int n; Foo() { cout << "\t\t\t" << this << endl; }
void* operator new( size_t n ) { void* p = ::operator new(n); cout << "\t\t\tNEW: " << n << " " << p << endl; return p; }
void* operator new[]( size_t n ) { void* p = ::operator new(n); cout << "\t\t\tNEW[]: " << n << " " << p << endl; return p; }
void operator delete[]( void* p,size_t n ) { cout << "\t\t\tDELETE[]: " << p << " " << n << endl << endl;}
void operator delete( void* p,size_t n ) { cout << "\t\t\tDELETE: " << p << " " << n << endl << endl;}
};

int main()
{

cout << "new Foo:" << endl;
Foo* f0 = new Foo;
cout << "\t\t\t" << sizeof(Foo) << endl;
delete f0;

cout << "new Foo[1]:" << endl;
Foo* f1 = new Foo[1];
cout << "\t\t\t" << sizeof(Foo[1]) << endl;
delete[] f1;

cout << "new Foo[2]:" << endl;
Foo* f2 = new Foo[2];
cout << "\t\t\t" << sizeof(Foo[2]) << endl;
delete[] f2;

cout << "new array< Foo,3 >:" << endl;
array< Foo,3 >* f3 = new array< Foo,3 >;
cout << "\t\t\t" << sizeof(*f3) << endl;
delete f3;

cout << "new array< Foo,3 >[1]:" << endl;
array< Foo,3 >* f4 = new array< Foo,3 >[1];
cout << "\t\t\t" << sizeof(*f4) << endl;
delete[] f4;

}

----
new Foo:
NEW: 4 0x1400047e0
0x1400047e0
4
DELETE: 0x1400047e0 4

new Foo[1]:
NEW[]: 12 0x140004c80
0x140004c88
4
DELETE[]: 0x140004c80 12

new Foo[2]:
NEW[]: 16 0x140004ca0
0x140004ca8
0x140004cac
8
DELETE[]: 0x140004ca0 16

new array< Foo,3 >:
ARRAY NEW: 12 0x140004cc0
0x140004cc0
0x140004cc4
0x140004cc8
12
ARRAY DELETE: 0x140004cc0 12

new array< Foo,3 >[1]:
ARRAY NEW[]: 20 0x140004ce0
0x140004ce8
0x140004cec
0x140004cf0
12
ARRAY DELETE[]: 0x140004ce0 20
----
> g++ -v
Reading specs from /usr/local/lib/gcc-lib/ia64-unknown-linux/3.0/specs
Configured with: ./configure
Thread model: single
gcc version 3.0
> g++ -o d d.cpp
> ./d
new Foo:
NEW: 4 0x6000000000001d50
0x6000000000001d50
4
DELETE: 0x6000000000001d50 4

new Foo[1]:
NEW[]: 12 0x6000000000001dc0
0x6000000000001dc8
4
DELETE[]: 0x6000000000001dc0 12

new Foo[2]:
NEW[]: 16 0x6000000000001de0
0x6000000000001de8
0x6000000000001dec
8
DELETE[]: 0x6000000000001de0 16

new array< Foo,3 >:
ARRAY NEW: 12 0x6000000000001e00
0x6000000000001e00
0x6000000000001e04
0x6000000000001e08
12
ARRAY DELETE: 0x6000000000001e00 12

new array< Foo,3 >[1]:
ARRAY NEW[]: 20 0x6000000000001e20
0x6000000000001e28
0x6000000000001e2c
0x6000000000001e30
12
ARRAY DELETE[]: 0x6000000000001e20 20
----
> g++ -v
Reading specs from /usr/lib/gcc-lib/ia64-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-101)
> g++ -o d d.cpp
> ./d
new Foo:
NEW: 4 0x6000000000002e80
0x6000000000002e80
4
DELETE: 0x6000000000002e80 4

new Foo[1]:
NEW[]: 12 0x6000000000002ea0
0x6000000000002ea8
4
DELETE[]: 0x6000000000002ea0 12

new Foo[2]:
NEW[]: 16 0x6000000000002ec0
0x6000000000002ec8
0x6000000000002ecc
8
DELETE[]: 0x6000000000002ec0 16

new array< Foo,3 >:
ARRAY NEW: 12 0x6000000000002ee0
0x6000000000002ee0
0x6000000000002ee4
0x6000000000002ee8
12
ARRAY DELETE: 0x6000000000002ee0 12

new array< Foo,3 >[1]:
ARRAY NEW[]: 20 0x6000000000002f00
0x6000000000002f08
0x6000000000002f0c
0x6000000000002f10
12
ARRAY DELETE[]: 0x6000000000002f00 20
---
E:\>cl /GX d.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.

d.cpp
Microsoft (R) Incremental Linker Version 7.00.9466
Copyright (C) Microsoft Corporation. All rights reserved.

/out:d.exe
d.obj

E:\>d
new Foo:
NEW: 4 00322F48
00322F48
4
DELETE: 00322F48 4

new Foo[1]:
NEW[]: 4 00322FD8
00322FD8
4
DELETE[]: 00322FD8 4

new Foo[2]:
NEW[]: 8 00322FE8
00322FE8
00322FEC
8
DELETE[]: 00322FE8 4
<BUG(*)>-----------------------------------^

new array< Foo,3 >:
ARRAY NEW: 12 00320F60
00320F60
00320F64
00320F68
12
ARRAY DELETE: 00320F60 12

new array< Foo,3 >[1]:
ARRAY NEW[]: 12 00320F78
00320F78
00320F7C
00320F80
12
ARRAY DELETE[]: 00320F78 12
---

regards,
alexander.

(*) Now try add ~Foo() { cout << "\t\t\t" << this << " dtor" << endl; }...

tom_usenet

unread,
Sep 17, 2002, 5:45:32 AM9/17/02
to
On Mon, 16 Sep 2002 19:43:40 +0200, NotFound <cor...@tengo.no> wrote:

>Karl Heinz Buchegger escribi=F3:


>
>> Well. I would be willing to pay that price.
>
>Then you can use always delete [], simply use always new x [1]; in lieu
>of new x;

But that requires you to use the default constructor, which is a
pretty major limitation.

Still, this whole argument is pretty moot, since why are people using
new[]/delete[] when std::vector provides a superior, if slightly more
resource hungry, alternative?

Tom

Karl Heinz Buchegger

unread,
Sep 17, 2002, 5:55:21 AM9/17/02
to

Victor Bazarov wrote:
>
>
> Here is my question: according to the Standard, you are supposed
> to delete[] even if you did "new blah[1]" (which supposedly has
> the same effect as "new blah"). Can we do a plain "delete" on
> a pointer to an array of one?

IMHO the answer is no.
The reason for this is, that the memory system may use a different
strategy for allocating arrays (even if they have a size of 1) then
for ordinary objects.

> Another facet of the same question:
> if I allocate one object using "new blah" (not an array), I must
> be able to say ptr[0] (because it's the same as *ptr), but may I
> use ptr + 1 as the "one past the end of the 'array'" or would it
> be an error (since it wasn't an array to begin with)?

No idea. Interesting question.

tom_usenet

unread,
Sep 17, 2002, 7:38:45 AM9/17/02
to
On Tue, 17 Sep 2002 11:55:21 +0200, Karl Heinz Buchegger
<kbuc...@gascad.at> wrote:

>
>
>Victor Bazarov wrote:
>>
>>
>> Here is my question: according to the Standard, you are supposed
>> to delete[] even if you did "new blah[1]" (which supposedly has
>> the same effect as "new blah"). Can we do a plain "delete" on
>> a pointer to an array of one?
>
>IMHO the answer is no.
>The reason for this is, that the memory system may use a different
>strategy for allocating arrays (even if they have a size of 1) then
>for ordinary objects.

And this is the whole point of the distinction between new and new[].
For an array the size has to be stored, but not for a non array. A
typical implementation of new[] will allocate an extra 4 bytes, put
the size in the first 4 allocated bytes, and then return a pointer to
then 5th byte.

delete[] will look back 4 bytes from the pointer given, get the size,
and use that to work out how many objects to destroy, and how much
memory to free.

new/delete obviously doesn't need these 4 extra bytes.

And what's wrong with std::vector if you don't want to worry about
new[]/delete[]? I don't even remember the last time I used new[] in
production code!

Tom

Alexander Terekhov

unread,
Sep 17, 2002, 10:33:00 AM9/17/02
to

tom_usenet wrote:
[...]

> Still, this whole argument is pretty moot, since why are people using
> new[]/delete[] when std::vector provides a superior, if slightly more
> resource hungry, alternative?

oh, yeah... std::deque aside,

http://groups.google.com/groups?selm=3D63F28C.BE3FE8B7%40web.de
(Subject: Re: assignment of auto_ptr temporaries)

---
Attila Feher wrote:
>
> Grzegorz Jablonski wrote:
> [SNIP]
> > BTW, why there is no standard
> > smart pointer for automatic deallocation of arrays?
>
> There is! It is called std::vector. ;-))) Really!

Really? ....
----

regards,
alexander.

tom_usenet

unread,
Sep 17, 2002, 12:29:47 PM9/17/02
to
On Tue, 17 Sep 2002 16:33:00 +0200, Alexander Terekhov
<tere...@web.de> wrote:

>
>tom_usenet wrote:
>[...]
>> Still, this whole argument is pretty moot, since why are people using
>> new[]/delete[] when std::vector provides a superior, if slightly more
>> resource hungry, alternative?
>
>oh, yeah... std::deque aside,

[snip unnecessary link to program demonstrating that, shock horror,
vectors have requirements on their held types, just in case we had
forgotten]

Are you suggesting that std::vector isn't superior to dynamic new[]ed
arrays in most cases?

Tom

Alexander Terekhov

unread,
Sep 17, 2002, 12:37:46 PM9/17/02
to

tom_usenet wrote:
[...]

> Are you suggesting that std::vector isn't superior to dynamic new[]ed
> arrays in most cases?

Uhmm, let me put it this way: what makes YOU think that std::vector IS

"superior" to dynamic new[]ed arrays "in most cases"?

regards,
alexander.

Neil Butterworth

unread,
Sep 17, 2002, 12:46:12 PM9/17/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3D875A5A...@web.de...

a) Exception safety
b) Range checking if you want it
c) Ability to find the size of the vector
d) Ability to assign the vector

NeilB


Alexander Terekhov

unread,
Sep 17, 2002, 1:20:24 PM9/17/02
to

Neil Butterworth wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote in message
> news:3D875A5A...@web.de...
> >
> > tom_usenet wrote:
> > [...]
> > > Are you suggesting that std::vector isn't superior to dynamic new[]ed
> > > arrays in most cases?
> >
> > Uhmm, let me put it this way: what makes YOU think that std::vector IS
> > "superior" to dynamic new[]ed arrays "in most cases"?
>
> a) Exception safety

Define "most cases" operations and specific guarantees, to begin with
[and see also (d) below].

> b) Range checking if you want it

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/MAN/MAN1/0100____.HTM

"....
-[no]check_bounds
Generates runtime code to check the values of array subscripts (and
equivalent pointer arithmetic involving pointers produced by converting
an array name to a pointer) to verify that the resulting address lies
within the range for which the C standard requires well-defined
behavior. The exact source code constructs that trigger these checks,
and the values used for a given bounds check, are not simple to
describe. In some cases the checks will trap on a partial address
computation even though the final result of the computation is within
bounds. A failed bounds check at runtime produces a Trace/BPT trap,
which may be caught by signal(SIGTRAP, handler). See the Programmer's
Guide for more details.

The -nocheck_bounds option (the default) disables the runtime checking
of array bounds.
...."

> c) Ability to find the size of the vector

Yes, but I can maintain it myself (if needed).

> d) Ability to assign the vector

Do you mean "value" semantics? Well, strcpy()-like stuff aside, it's
kinda solvable using smart array pointers/owners (and those are much
more "flexible"/etc. than std::stuff, AFAICS).

AND YES: if what you need IS std::vector (deque is probably better
"in most cases") then I see NO problems (silly implementations and
things like thread cancel/exit and "catch(...)" interactions aside)
using it. That doesn't mean that one should simply forget arrays
"forever", however.

regards,
alexander.

Andrey Tarasevich

unread,
Sep 17, 2002, 1:27:25 PM9/17/02
to
tom_usenet wrote:
> ...

> Are you suggesting that std::vector isn't superior to dynamic new[]ed
> arrays in most cases?
> ...

In what "most cases"? If you take the C++ programming in its entirety, i.e.
drop in one bucket every area of computer programming that uses the language
and thoroughly mix it together, then you'll probably end up with homogeneous
mass where 'std::vector' is superior "in most cases". That, however, won't
change the fact that in performance-critical and memory-critical programming
the overheads introduced by 'std::vector' could be a serious burden. I work
in ECAD area, and in ECAD area you use 'std::vector' when you need a
_resizable_ array. When you need a fixed-size array you use either an
explicitly declared array (compile-time size) or a new[]'ed array (run-time
size). (Yes, it is always a good idea to hide these arrays inside some
wrapper classes). I can't waste precious memory on storing the current array
size inside array class , as 'std::vector' does (in the debug version of the
program it could be useful, but in the release I can't afford it). I can't
waste memory on storing 'std::allocator' subobject (as long as it is
_aggregated_, not inherited, into 'std::vector' it will occupy memory, even
if it has no data fields). And don't tell me that "memory is cheap and you
can always add more". With the amounts of data processed by modern programs
you can easily run out of application's _address_ _space_. Adding memory
can't help here.

Neil Butterworth

unread,
Sep 17, 2002, 1:28:24 PM9/17/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3D876458...@web.de...

>
> Neil Butterworth wrote:
> >
> > "Alexander Terekhov" <tere...@web.de> wrote in message
> > news:3D875A5A...@web.de...
> > >
> > > tom_usenet wrote:
> > > [...]
> > > > Are you suggesting that std::vector isn't superior to dynamic
new[]ed
> > > > arrays in most cases?
> > >
> > > Uhmm, let me put it this way: what makes YOU think that std::vector IS
> > > "superior" to dynamic new[]ed arrays "in most cases"?
> >
> > a) Exception safety
>
> Define "most cases" operations and specific guarantees, to begin with
> [and see also (d) below].

That makes no sense.

So what? Do you claim that this is a feature of Standard C++?

>
> > c) Ability to find the size of the vector
>
> Yes, but I can maintain it myself (if needed).

Yes, you can write your own version of std::vector. What a good use of your
time!

>
> > d) Ability to assign the vector
>
> Do you mean "value" semantics? Well, strcpy()-like stuff aside
> , it's
> kinda solvable using smart array pointers/owners (and those are much
> more "flexible"/etc. than std::stuff, AFAICS).

Nonsense.

> AND YES: if what you need IS std::vector (deque is probably better
> "in most cases") then I see NO problems (silly implementations and
> things like thread cancel/exit and "catch(...)" interactions aside)
> using it. That doesn't mean that one should simply forget arrays
> "forever", however.

Nobody was suggesting you should.

NeilB

Andrew Koenig

unread,
Sep 17, 2002, 1:27:19 PM9/17/02
to
>> Uhmm, let me put it this way: what makes YOU think that std::vector IS
>> "superior" to dynamic new[]ed arrays "in most cases"?

Neil> a) Exception safety
Neil> b) Range checking if you want it
Neil> c) Ability to find the size of the vector
Neil> d) Ability to assign the vector

e) Efficient append operation (push_back) that extends the size
automatically.
f) Automatic destruction on block exit when the vector
is a local variable.

--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark

Alexander Terekhov

unread,
Sep 17, 2002, 1:44:28 PM9/17/02
to

Neil Butterworth wrote:
[...]

> > > a) Exception safety
> >
> > Define "most cases" operations and specific guarantees, to begin with
> > [and see also (d) below].
>
> That makes no sense.

What's your problem with C-style {new[]ed} arrays and
"Exception safety", Neil?

> > > b) Range checking if you want it

[...-[no]check_bounds...]

> So what? Do you claim that this is a feature of Standard C++?

No. Do you claim that you ALWAYS use at() and NEVER
use [], "safety" of iterators aside for a moment?

> > > c) Ability to find the size of the vector
> >
> > Yes, but I can maintain it myself (if needed).
>
> Yes, you can write your own version of std::vector. What a good use of your
> time!

It is NOT entirely bad use of time, IMO. ;-)

regards,
alexander.

Neil Butterworth

unread,
Sep 17, 2002, 1:54:05 PM9/17/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3D8769FC...@web.de...

>
> Neil Butterworth wrote:
> [...]
> > > > a) Exception safety
> > >
> > > Define "most cases" operations and specific guarantees, to begin with
> > > [and see also (d) below].
> >
> > That makes no sense.
>
> What's your problem with C-style {new[]ed} arrays and
> "Exception safety", Neil?

Please explain what youy mean by this, in English and without quoting reams
of non-relevant stuff from non-relevant newsgroups. Are you saying you can
acchieve exception safety with new'd arrays without writing more code than
you would if you used a vector? If so, I'd like to see the code.

>
> > > > b) Range checking if you want it
>
> [...-[no]check_bounds...]
>
> > So what? Do you claim that this is a feature of Standard C++?
>
> No. Do you claim that you ALWAYS use at()

Nope - I never use it.

> and NEVER
> use [], "safety" of iterators aside for a moment?

But what has this got to do with you posting the man page for a compiler?

> > > > c) Ability to find the size of the vector
> > >
> > > Yes, but I can maintain it myself (if needed).
> >
> > Yes, you can write your own version of std::vector. What a good use of
your
> > time!
>
> It is NOT entirely bad use of time, IMO. ;-)

We differ there then.


NeilB


Alexander Terekhov

unread,
Sep 17, 2002, 1:59:42 PM9/17/02
to

Andrew Koenig wrote:
[...]

> e) Efficient append operation (push_back) that extends the size
> automatically.

TC1 and excess capacity aside, that's std::deque, unless I'm just
missing something.

> f) Automatic destruction on block exit when the vector
> is a local variable.

That's hypothetical std::auto_array_ptr<> and alike beasts.

regards,
alexander.

Alexander Terekhov

unread,
Sep 17, 2002, 2:22:18 PM9/17/02
to

Neil Butterworth wrote:
[...]

> > What's your problem with C-style {new[]ed} arrays and
> > "Exception safety", Neil?
>
> Please explain what youy mean by this, in English and without quoting reams
> of non-relevant stuff from non-relevant newsgroups. Are you saying you can
> acchieve exception safety with new'd arrays without writing more code than
> you would if you used a vector? If so, I'd like to see the code.

You'd like to see auto_array_ptr<> code? ;-)

> > > > > b) Range checking if you want it
> >
> > [...-[no]check_bounds...]
> >
> > > So what? Do you claim that this is a feature of Standard C++?
> >
> > No. Do you claim that you ALWAYS use at()
>
> Nope - I never use it.
>
> > and NEVER
> > use [], "safety" of iterators aside for a moment?
>
> But what has this got to do with you posting the man page for a compiler?

man page I've posted explains what needs to be done in order to have
some checking in place that would throw "pthread_exc_subrng_e Unhandled
subscript out of range exception" (or so) under this particular threaded
C/C++ implementation -- ``Range checking if you want it.'' The standard
C++ way to get std::out_of_range exception w.r.t. vectors is to use at()
(thing you never use), AFAIK. Is this clear enough now?

regards,
alexander.

Andrew Koenig

unread,
Sep 17, 2002, 2:44:23 PM9/17/02
to
>> e) Efficient append operation (push_back) that extends the size
>> automatically.

Alexander> TC1 and excess capacity aside, that's std::deque, unless
Alexander> I'm just missing something.

You're missing something. If v is a vector, v.push_back(x) appends a
copy of x efficiently to v.

By ``efficiently,'' I mean the following:

1) If v.size() != v.capacity(), v.push_back(x) takes O(1) time.

2) Successive use of v.push_back to expand an initially
empty vector to any size takes no more than a constant
multiple of the time it takes to preallocate the vector.

>> f) Automatic destruction on block exit when the vector
>> is a local variable.

Alexander> That's hypothetical std::auto_array_ptr<> and alike beasts.

Hypothetical? Not at all:

{
vector<string> v;

// ...

// v and all of its elements are destroyed here
// authomatically.

Andre Kostur

unread,
Sep 17, 2002, 3:25:49 PM9/17/02
to
Alexander Terekhov <tere...@web.de> wrote in
news:3D876458...@web.de:

>
> Neil Butterworth wrote:
>>
>> "Alexander Terekhov" <tere...@web.de> wrote in message
>> news:3D875A5A...@web.de...
>> >
>> > tom_usenet wrote:
>> > [...]
>> > > Are you suggesting that std::vector isn't superior to dynamic
>> > > new[]ed arrays in most cases?
>> >
>> > Uhmm, let me put it this way: what makes YOU think that std::vector
>> > IS "superior" to dynamic new[]ed arrays "in most cases"?
>>
>> a) Exception safety
>
> Define "most cases" operations and specific guarantees, to begin with
> [and see also (d) below].
>
>> b) Range checking if you want it
>
> http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/M
> AN/MAN1/0100____.HTM
>

[snip platform-specific compiler switches]

Stick to Standard C++ please....

Alexander Terekhov

unread,
Sep 17, 2002, 4:16:05 PM9/17/02
to

Andrew Koenig wrote:
>
> >> e) Efficient append operation (push_back) that extends the size
> >> automatically.
>
> Alexander> TC1 and excess capacity aside, that's std::deque, unless
> Alexander> I'm just missing something.
>
> You're missing something. If v is a vector, v.push_back(x) appends a
> copy of x efficiently to v.
>
> By ``efficiently,'' I mean the following:
>
> 1) If v.size() != v.capacity(), v.push_back(x) takes O(1) time.
>
> 2) Successive use of v.push_back to expand an initially
> empty vector to any size takes no more than a constant
> multiple of the time it takes to preallocate the vector.

Uhmm, but ("objects to be stored contiguously" aside): "A deque is
a kind of sequence that, like a vector (23.2.4), supports random
access iterators. In addition, it supports constant time insert and
erase operations at the beginning or the end; insert and erase in
the middle take linear time. That is, a deque is especially optimized
for pushing and popping elements at the beginning and end. As with
vectors, storage management is handled automatically." and "Inserting
a single element either at the beginning or end of a deque always
takes constant time and causes a single call to the copy constructor
of T."

> >> f) Automatic destruction on block exit when the vector
> >> is a local variable.
>
> Alexander> That's hypothetical std::auto_array_ptr<> and alike beasts.
>
> Hypothetical? Not at all:
>
> {
> vector<string> v;
>
> // ...
>
> // v and all of its elements are destroyed here
> // authomatically.
> }

Well, {
auto_array_ptr< vector<string> > aap_vs( some_aap_vs_source(/**/) );

// ...

// aap_vs and all of its elements are destroyed here
// automatically.
}

Oder? ;-)

regards,
alexander.

Andrew Koenig

unread,
Sep 17, 2002, 4:40:46 PM9/17/02
to
>> 2) Successive use of v.push_back to expand an initially
>> empty vector to any size takes no more than a constant
>> multiple of the time it takes to preallocate the vector.

Alexander> Uhmm, but ("objects to be stored contiguously" aside): "A
Alexander> deque is a kind of sequence that, like a vector (23.2.4),
Alexander> supports random access iterators. In addition, it supports
Alexander> constant time insert and erase operations at the beginning
Alexander> or the end; insert and erase in the middle take linear
Alexander> time. That is, a deque is especially optimized for pushing
Alexander> and popping elements at the beginning and end. As with
Alexander> vectors, storage management is handled automatically." and
Alexander> "Inserting a single element either at the beginning or end
Alexander> of a deque always takes constant time and causes a single
Alexander> call to the copy constructor of T."

What's your point?

Alexander> Well, {
Alexander> auto_array_ptr< vector<string> > aap_vs( some_aap_vs_source(/**/) );

Alexander> // ...

Alexander> // aap_vs and all of its elements are destroyed here
Alexander> // automatically.
Alexander> }

Again, what's your point?

tom_usenet

unread,
Sep 18, 2002, 5:32:00 AM9/18/02
to

But typically the memory used by the array encapsulated by the vector
far outweighs the memory overhead of the vector itself (which is
probably 12 bytes more than a plain pointer). If your vectors are less
than 50 bytes or so, then you may notice the extra overhead.
Otherwise, you probably won't.

Tom

Alexander Terekhov

unread,
Sep 18, 2002, 5:39:35 AM9/18/02
to

Andrew Koenig wrote:
>
> >> 2) Successive use of v.push_back to expand an initially
> >> empty vector to any size takes no more than a constant
> >> multiple of the time it takes to preallocate the vector.
>
> Alexander> Uhmm, but ("objects to be stored contiguously" aside): "A
> Alexander> deque is a kind of sequence that, like a vector (23.2.4),
> Alexander> supports random access iterators. In addition, it supports
> Alexander> constant time insert and erase operations at the beginning
> Alexander> or the end; insert and erase in the middle take linear
> Alexander> time. That is, a deque is especially optimized for pushing
> Alexander> and popping elements at the beginning and end. As with
> Alexander> vectors, storage management is handled automatically." and
> Alexander> "Inserting a single element either at the beginning or end
> Alexander> of a deque always takes constant time and causes a single
> Alexander> call to the copy constructor of T."
>
> What's your point?

My point is this:

: > e) Efficient append operation (push_back) that extends the size


: > automatically.
:
: TC1 and excess capacity aside, that's std::deque, unless I'm just
: missing something.

IOW, if one really needs "Efficient append operation (push_back) that
extends the size automatically" with random access to objects/elements
and doesn't really need TC1's "objects to be stored contiguously" vector
requirement (feature), then something along the lines of std::deque is
probably more reasonable and better choice. (unless I'm just missing
something ;-) perhaps: template <class T, class Container = vector<T> >
class stack... )

> Alexander> Well, {
> Alexander> auto_array_ptr< vector<string> > aap_vs( some_aap_vs_source(/**/) );
>
> Alexander> // ...
>
> Alexander> // aap_vs and all of its elements are destroyed here
> Alexander> // automatically.
> Alexander> }
>
> Again, what's your point?

My point is this:

: > f) Automatic destruction on block exit when the vector


: > is a local variable.
:
: That's hypothetical std::auto_array_ptr<> and alike beasts.

IOW, it's just an overkill to use vectors to ensure automatic delete[]
only (NOT using any other feature provided by std::vector and which
make it ``more/better than new[]-ed array''), IMO.

regards,
alexander.

Reply all
Reply to author
Forward
0 new messages