Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What is the sense of placement new[] operator ?

6 views
Skip to first unread message

Mirek Fidler

unread,
Oct 30, 2002, 6:18:36 PM10/30/02
to
Hi,

while there is a very good use for placement new in form

char buffer[sizeof(Foo)];

Foo *p = new(buffer) Foo;

I am unable to imagine how placement new[] could be used

char buffer[sizeof(Foo) * 10];

Foo *p = new(buffer) Foo[10];

is invalid, because new may request more than sizeof(Foo) * 10 bytes (in
order to store number of objects).

So what is the purpose of placement new[] ?

Mirek

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Thomas Richter

unread,
Oct 31, 2002, 8:29:07 AM10/31/02
to
Hi Mirek,

> So what is the purpose of placement new[] ?

They point is that the "buffer" argument of the placement operators need not
to be used to point the memory to place the object at. A frequent use for this
argument is also to specify some "memory manager" that performs the allocation
of specialized objects in specialized environments. To give an example, a
video driver could use a placement new operator to allocate video memory of a
graphics board (i.e. for texture buffers or whatever...).

So long,
Thomas

Mark Charsley

unread,
Oct 31, 2002, 2:14:44 PM10/31/02
to
In article <apph1k$2clq$1...@news.vol.cz>, c...@centrum.cz (Mirek Fidler)
wrote:

> Hi,
>
> while there is a very good use for placement new in form
>
> char buffer[sizeof(Foo)];
>
> Foo *p = new(buffer) Foo;
>
> I am unable to imagine how placement new[] could be used
>
> char buffer[sizeof(Foo) * 10];
>
> Foo *p = new(buffer) Foo[10];
>
> is invalid, because new may request more than sizeof(Foo) * 10
> bytes (in
> order to store number of objects).
>
> So what is the purpose of placement new[] ?

So it works with calloc?

buffer = calloc(sizeof(Foo),10);


Foo *p = new(buffer) Foo[10];

Mark

Mirek Fidler

unread,
Nov 1, 2002, 2:15:41 PM11/1/02
to
> > So what is the purpose of placement new[] ?
>
> They point is that the "buffer" argument of the placement operators
need
not
> to be used to point the memory to place the object at. A frequent use
for
this
> argument is also to specify some "memory manager" that performs the
allocation
> of specialized objects in specialized environments. To give an
example, a
> video driver could use a placement new operator to allocate video
memory
of a
> graphics board (i.e. for texture buffers or whatever...).

No problem with normal placement new.

But how you can do this with placement new[] ?! ISO C++ AFAIK does
not
even guarantee that if you do

int *ports = new(AddressOfPorts) int[10];

that port[0] will be at AddressOfPorts....

Only conclusion here is that only sense of operator new[] is to
support
undefined behaviour... :) (In fact, port[0] will likely be at
AddressOfPorts, because int is POD and does not need destruction, but
there
is no guarantee in ISOC++).

Mirek

Mirek Fidler

unread,
Nov 1, 2002, 2:21:34 PM11/1/02
to
> > So what is the purpose of placement new[] ?
>
> So it works with calloc?
>
> buffer = calloc(sizeof(Foo),10);
> Foo *p = new(buffer) Foo[10];

No, this will not work. Calloc simply allocates sizeof(Foo) * 10. new
may require more.

Mirek

llewelly

unread,
Nov 1, 2002, 4:52:09 PM11/1/02
to
"Mirek Fidler" <c...@centrum.cz> writes:

> Hi,
>
> while there is a very good use for placement new in form
>
> char buffer[sizeof(Foo)];
>
> Foo *p = new(buffer) Foo;
>
> I am unable to imagine how placement new[] could be used
>
> char buffer[sizeof(Foo) * 10];
>
> Foo *p = new(buffer) Foo[10];
>
> is invalid, because new may request more than sizeof(Foo) * 10
bytes (in
> order to store number of objects).

Placement new[] (array form) does not request memory at all. It
constructs objects you specify in the memory you specify. You must
have it mixed up with non-placement new[] .

> So what is the purpose of placement new[] ?

Same as placement new, but for arrays.

Mirek Fidler

unread,
Nov 2, 2002, 1:06:02 PM11/2/02
to
> > I am unable to imagine how placement new[] could be used
> >
> > char buffer[sizeof(Foo) * 10];
> >
> > Foo *p = new(buffer) Foo[10];
> >
> > is invalid, because new may request more than sizeof(Foo) * 10
> bytes (in
> > order to store number of objects).
>
> Placement new[] (array form) does not request memory at all. It
> constructs objects you specify in the memory you specify. You must
> have it mixed up with non-placement new[] .
>
> > So what is the purpose of placement new[] ?
>
> Same as placement new, but for arrays.

See example above and think about it.

Problem is that there is no way how to determine amount of memory
needed, AFAIK. ISO C++ only says, that amount of memory will be sizeof(T) +
zero or positive number.

Mirek

Hillel Y. Sims

unread,
Nov 3, 2002, 12:31:39 PM11/3/02
to

"Mirek Fidler" <c...@centrum.cz> wrote in message
news:aq0ddd$ia0$1...@news.vol.cz...
> "llewelly" <llewe...@xmission.dot.com> wrote in message
news:861y65o...@Zorthluthik.foo...


> > > I am unable to imagine how placement new[] could be used
> > >
> > > char buffer[sizeof(Foo) * 10];
> > >
> > > Foo *p = new(buffer) Foo[10];
> > >
> > > is invalid, because new may request more than sizeof(Foo) * 10
> > bytes (in
> > > order to store number of objects).
> >
> > Placement new[] (array form) does not request memory at all. It
> > constructs objects you specify in the memory you specify. You
must
> > have it mixed up with non-placement new[] .
> >
> > > So what is the purpose of placement new[] ?
> >
> > Same as placement new, but for arrays.
>
> See example above and think about it.
>
> Problem is that there is no way how to determine amount of memory
> needed, AFAIK. ISO C++ only says, that amount of memory will be
sizeof(T)
+
> zero or positive number.

I believe llewelly is correct. Placement new[] form does _not_ allocate
any
memory, and therefore extra memory to account for the number of elements
is
not necessarily required as part of the buffer used to construct the
objects -- since the memory buffer is managed externally, it is
necessary
only that the buffer contains (sizeof(T) * n) bytes.

int *p = new int[10]; // amount of memory allocated is probably >
sizeof(int) * 10
delete[] p; // which is why it is necessary to use delete[] instead of
just
delete..

void* buf = malloc(sizeof(int) * 10);
new (buf) int[10]; // memory is _not_ allocated here
free(buf);

hys

--
Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

Mirek Fidler

unread,
Nov 3, 2002, 8:48:37 PM11/3/02
to
> I believe llewelly is correct. Placement new[] form does _not_ allocate
> any
> memory, and therefore extra memory to account for the number of elements
> is
> not necessarily required as part of the buffer used to construct the
> objects -- since the memory buffer is managed externally, it is
> necessary
> only that the buffer contains (sizeof(T) * n) bytes.

Man, problem is not about alocating memory. Problem is about amount of
memory new expects to be in prealocated buffer.

See, new functionality is defined in core language. Placement new is
defined in library. There is no way how compiler could distinguish between
'new' forms.

> int *p = new int[10]; // amount of memory allocated is probably >
> sizeof(int) * 10
> delete[] p; // which is why it is necessary to use delete[] instead of
> just
> delete..
>
> void* buf = malloc(sizeof(int) * 10);
> new (buf) int[10]; // memory is _not_ allocated here
> free(buf);

Replace int with class with destructor and try

assert(new (buf) int[10] == buf);

Perhaps that will tell you something ;)

Sure it could be bug in my compilers, but carefuly reading ISO C++
standard, it is not bug. Placement new[] is simply unusable.

Mirek

Hillel Y. Sims

unread,
Nov 4, 2002, 11:19:27 AM11/4/02
to

"Hillel Y. Sims" <use...@phatbasset.com> wrote in message
news:0c3x9.36832$S44....@news4.srv.hcvlny.cv.net...

On the other hand, I built and tested the sample code you presented in
comp.std.c++ regarding this subject, and it failed the assert that the
result of operator new[](void*) -- on my system it placed the count of
objects in the first 8 bytes of the preallocated buffer. That makes
sense
for non-placement operator new[], when the runtime itself needs to track
the
number of objects, but I don't see why it would need to do that for
placement operator new[], and it does indeed seem to make placement
operator
new[] pretty much useless (unless it's just a compiler bug?).

hys

--
(c) 2002 Hillel Y. Sims

Thomas Richter

unread,
Nov 4, 2002, 12:21:21 PM11/4/02
to
Hi,

>> > So what is the purpose of placement new[] ?
>
> > They point is that the "buffer" argument of the placement operators need
> > not to be used to point the memory to place the object at. A frequent use
> > for this argument is also to specify some "memory manager" that
> > performs the allocation of specialized objects in specialized
> > environments. To give an example, a video driver could use a
> > placement new operator to allocate video memory of a graphics board
> > (i.e. for texture buffers or whatever...).
>
> No problem with normal placement new.

> But how you can do this with placement new[] ?! ISO C++ AFAIK does
> not even guarantee that if you do

> int *ports = new(AddressOfPorts) int[10];

> that port[0] will be at AddressOfPorts....

Yes, but so what? Please see my post above: "AddressOfPorts" would be *not*
the address of the memory to take a chunk from. It would be the pointer to
a class that allocates memory for you *from* the special purpose address
space, and the hardware memory is managed inside, hidden by the allocator
class. It is a matter how you implement the placement new[] operator.

Meaning: The above does not guarantee you that port[0] will be pointing to
a specific address. However, new[] could be implemented in a way that
port[0] resides in special purpose memory (e.g. graphics memory).

So long,
Thomas

Thomas Richter

unread,
Nov 4, 2002, 1:31:32 PM11/4/02
to

Hi,

> I believe llewelly is correct. Placement new[] form does _not_ allocate
> any memory,

Even that is not correct. It is up to the implementation of this
new[] operator. Of course it could allocate memory if you write it in
this way.

An example code from "real life": "Environ" is a memory manager class
and implements private memory allocation methods by means of a method
called "AllocMem()". The following is an overloaded operator new[] for
this new memory manager:

void *operator new[](size_t size,class Environ *env)
{
struct MemoryHolder *mem;
// Keep the memory holder here as well
size += sizeof(struct MemoryHolder);
// Now allocate the memory from the environment.
mem = (struct MemoryHolder *)env->AllocMem(size);
// Install the environment pointer and (possibly) the size
mem->mh_pEnviron = env;
mem->mh_ulSize = size;
return (void *)(mem + 1);
}

> and therefore extra memory to account for the number of elements
> is not necessarily required as part of the buffer used to construct the
> objects -- since the memory buffer is managed externally,

^^^^^^^^^^^^^^^^^^

"externally" is not quite the proper word. "Managed by the implementation
of the operator" would be better. The "default implementation" would just
return the "void *" passed in as second argument, but you can clearly
overload this, as in the example above.

So long,
Thomas

Thomas Richter

unread,
Nov 4, 2002, 4:17:24 PM11/4/02
to

Hi,


> On the other hand, I built and tested the sample code you presented in
> comp.std.c++ regarding this subject, and it failed the assert that the
> result of operator new[](void*) -- on my system it placed the count of
> objects in the first 8 bytes of the preallocated buffer. That makes
> sense for non-placement operator new[], when the runtime itself needs to track
> the number of objects,

So it does for the placement new. It has to know the number of objects to
call the destructors for on the corresponding delete[] should you call it.

"placement new" is just one implementation of "new with arguments", the
latter being a non-standard name. See my post above to understand what it
could be used for.

So long,
Thomas

Hyman Rosen

unread,
Nov 4, 2002, 4:21:09 PM11/4/02
to
Hillel Y. Sims wrote:
> I don't see why it would need to do that for placement operator new[],
> and it does indeed seem to make placement operator new[] pretty much
> useless

When you call delete[] on the allocated array, the compiler needs to
know how many elements to destruct. I don't see why it's useless;
either your compiler documentation or a little experimentation will
tell you how much extra space you need.

If you don't want that, you need to use std::vector's approach -
allocate the storage then use regular placement new on each element.
That puts the onus of keeping track of the size on you.

Mark Charsley

unread,
Nov 5, 2002, 3:09:05 PM11/5/02
to
In article <aps7a2$rer$1...@news.vol.cz>, c...@centrum.cz (Mirek Fidler)
wrote:

> > > So what is the purpose of placement new[] ?


> >
> > So it works with calloc?
> >
> > buffer = calloc(sizeof(Foo),10);
> > Foo *p = new(buffer) Foo[10];
>
> No, this will not work. Calloc simply allocates sizeof(Foo) * 10. new
> may require more.

Are you sure: it makes the presence of calloc rather pointless if this is
the case. I assumed the whole point of calloc was to ensure that the
returned memory was sufficient to hold n correctly aligned Foo's. Whereas
malloc(n*sizeof(Foo)) would only guarantee that the first Foo would be
correcly aligned.

Mark

Markus Mauhart

unread,
Nov 5, 2002, 4:47:47 PM11/5/02
to
"Thomas Richter" <th...@cleopatra.math.tu-berlin.de> wrote ...
[explaining how to use new-placement syntax to call a userdefined]
[global operator new[] function with userdefined signature]

>
> > int *ports = new(AddressOfPorts) int[10];
>
> > that port[0] will be at AddressOfPorts....
>
> Yes, but so what? Please see my post above: "AddressOfPorts" would be *not*
> the address of the memory to take a chunk from. It would be the pointer to
> a class that allocates memory for you *from* the special purpose address
> space, and the hardware memory is managed inside, hidden by the allocator
> class. It is a matter how you implement the placement new[] operator.
>
> Meaning: The above does not guarantee you that port[0] will be pointing to
> a specific address. However, new[] could be implemented in a way that
> port[0] resides in special purpose memory (e.g. graphics memory).


"Thomas Richter" <th...@cleopatra.math.tu-berlin.de> wrote ...


>
> > objects in the first 8 bytes of the preallocated buffer. That makes
> > sense for non-placement operator new[], when the runtime itself needs to track
> > the number of objects,
>
> So it does for the placement new. It has to know the number of objects to
> call the destructors for on the corresponding delete[] should you call it.

? (see below)


"Hyman Rosen" <hyr...@mail.com> wrote ...


> Hillel Y. Sims wrote:
> > I don't see why it would need to do that for placement operator new[],
> > and it does indeed seem to make placement operator new[] pretty much
> > useless
>

> When you call delete[] on the allocated array, the compiler needs to
> know how many elements to destruct.


This is what I dont understand: how can you use a delete[]-expression
on the allocated array ?

We had two different situations in this thread:

1) Mirek Fidler's original:

void* pv = ...;
T* pt = new (pv) T [123];//any T, e.g. T=int
// -> allocating through stdc++-lib's "::operator new [] (size_t,void*)"

2) Thomas Richter's version for allocation of e.g. graphics RAM:

VGA_ALLOC* pvga_alloc = ...;
T* pt = new (pvga_alloc) T [123];//any T, e.g. T=int
// -> allocating through userdefined "::operator new [] (size_t,VGA_ALLOC*)"

Now what shall be the corresponding delete[] expression that could
use the hidden number of elements ?


Thanks,
Markus.

Mirek Fidler

unread,
Nov 5, 2002, 5:11:00 PM11/5/02
to
> > > So it works with calloc?
> > >
> > > buffer = calloc(sizeof(Foo),10);
> > > Foo *p = new(buffer) Foo[10];
> >
> > No, this will not work. Calloc simply allocates sizeof(Foo) * 10. new
> > may require more.
>
> Are you sure: it makes the presence of calloc rather pointless if this is
> the case. I assumed the whole point of calloc was to ensure that the
> returned memory was sufficient to hold n correctly aligned Foo's.

Yes. But correct alignment is not an issue here.

> Whereas malloc(n*sizeof(Foo)) would only guarantee that the first Foo
would be
> correcly aligned.

If first Foo is aligned, than any other is aligned too. That is because
sizeof itself is aligned.

Mirek

Hyman Rosen

unread,
Nov 6, 2002, 2:49:03 PM11/6/02
to
Markus Mauhart wrote:
> Now what shall be the corresponding delete[] expression that could
> use the hidden number of elements ?

Ouch. In further evidence of the problem, my contrived example
is wrong. Let's try again:

#include <memory>
#include <iostream>

void *save;

struct X
{
virtual ~X() { std::cout << "Bye!\n"; }
void *operator new[](size_t n) { return save = ::operator new(n); }
void operator delete[](void *p) { ::operator delete(p); }
};

int main()
{
X *p = new X[1];
p[0].~X();
::new (save) X[1];
delete[] p;

llewelly

unread,
Nov 6, 2002, 3:27:34 PM11/6/02
to
"Mirek Fidler" <c...@centrum.cz> writes:

> > > I am unable to imagine how placement new[] could be used
> > >
> > > char buffer[sizeof(Foo) * 10];
> > >
> > > Foo *p = new(buffer) Foo[10];
> > >
> > > is invalid, because new may request more than sizeof(Foo) * 10
> > bytes (in
> > > order to store number of objects).

I went looking in the standard and found support for your
position. (See below).

> >
> > Placement new[] (array form) does not request memory at all. It
> > constructs objects you specify in the memory you specify. You must
> > have it mixed up with non-placement new[] .
> >
> > > So what is the purpose of placement new[] ?
> >
> > Same as placement new, but for arrays.
>
> See example above and think about it.
>
> Problem is that there is no way how to determine amount of memory
> needed,

My reading of 5.3.4/10 leads me to belive that the amount of memory
needed will be provided to placement new[]'s allocation
function. If you replace that allocation function, you'll have
that value. Depending on your use of placement new[], you may or
may not be able to handle a size larger than
sizeof(T)*array_elements, but if an implemetention requests such a
size, you'll know what that size is. So use of placement new[] is
more involved than I thought, but it isn't useless.

The first few lines of 5.3.4/10:

# A new-expression passes the amount of space requested to the
# allocation function as the first argument of type std::size_t. That
# aargument shall be no less than the size of the object being
# created; it may be greater than the size of the object being
# created only if the object is an array.

There's more in 5.3.4/10 about the alignment requirements of arrays of
char allocated by new, but I don't think it's relevant to our
discussion.

> AFAIK. ISO C++ only says, that amount of memory will be sizeof(T) +
> zero or positive number.

[snip]

Mirek Fidler

unread,
Nov 6, 2002, 4:06:03 PM11/6/02
to

> We had two different situations in this thread:
>
> 1) Mirek Fidler's original:
>
> void* pv = ...;
> T* pt = new (pv) T [123];//any T, e.g. T=int
> // -> allocating through stdc++-lib's "::operator new []
(size_t,void*)"
>
> Now what shall be the corresponding delete[] expression that could
> use the hidden number of elements ?

Quite strangely, there is no such delete[] expression. Nevertheless,
C++
still has to store number of elements, because he does not know it :)

It is because other placement forms (with placement form, you can
substitute 'new with more arguments') may allocate on normal heap and
then
it is possible to use normal delete/delete[] to deallocate it.

Standard library example is:

void* operator new[](std::size_t size, const std::nothrow_t&)
throw();

Memory allocated with this form is deallocated with normal delete[].

Frankly, this is somewhat grey zone of C++ :)

Mirek

Hyman Rosen

unread,
Nov 6, 2002, 4:11:11 PM11/6/02
to
Markus Mauhart wrote:
> Now what shall be the corresponding delete[] expression that could
> use the hidden number of elements ?

OK, let's contrive something :-) The following is even portable
if array new always uses the same extra amount of space for a
given type.

#include <memory>
#include <iostream>

struct X
{
virtual ~X() { std::cout << "Bye!\n"; }

void *operator new[](size_t n) { return ::operator new(n); }


void operator delete[](void *p) { ::operator delete(p); }
};

int main()
{
X *p = new X[1];
p[0].~X();

::new (p) X[1];
delete[] p;

Mirek Fidler

unread,
Nov 7, 2002, 3:04:36 AM11/7/02
to
> > Now what shall be the corresponding delete[] expression that could
> > use the hidden number of elements ?
>
> OK, let's contrive something :-) The following is even portable
> if array new always uses the same extra amount of space for a
> given type.

Sadly, ISO C++ does not guarantee even that...

Mirek

Markus Mauhart

unread,
Nov 7, 2002, 4:35:08 PM11/7/02
to
"Hyman Rosen" <hyr...@mail.com> wrote ...
>
> OK, let's contrive something :-) The following is even portable
> if array new always uses the same extra amount of space for a
> given type.

??
Ignoring portability, but your 1st version IMHO worked through
the elegant global 'void* save', so this version cant work, or ?

>
> #include <memory>
> #include <iostream>
>
#include <cassert>
void* save;


> struct X
> {
> virtual ~X() { std::cout << "Bye!\n"; }

//> void *operator new[](size_t n) { return ::operator new(n); }
void *operator new[](size_t n) { return save = ::operator new(n);


}
> void operator delete[](void *p) { ::operator delete(p); }
> };
>
> int main()
> {
> X *p = new X[1];
> p[0].~X();

assert (save == (void*)p);

Mark Charsley

unread,
Nov 7, 2002, 8:56:23 PM11/7/02
to
In article <aq999t$k0n$1...@news.vol.cz>, c...@centrum.cz (Mirek Fidler)
wrote:

> If first Foo is aligned, than any other is aligned too. That is

> because
> sizeof itself is aligned.

<checks, looks surprised>

Yup you're right. So given that calloc(x,y) can be implemented as
malloc(x*y), does anyone know what purpose it serves?

Mark

Mirek Fidler

unread,
Nov 8, 2002, 11:26:13 AM11/8/02
to
> <checks, looks surprised>
>
> Yup you're right. So given that calloc(x,y) can be implemented as
> malloc(x*y), does anyone know what purpose it serves?

None practical, especially from C++ point of view.

It is rather old-days-C fossil..

Mirek

Hyman Rosen

unread,
Nov 8, 2002, 1:37:35 PM11/8/02
to
Markus Mauhart wrote:
> Ignoring portability, but your 1st version IMHO worked through
> the elegant global 'void* save', so this version cant work, or ?

My messages must have gotten crossed in time.
The "elegeant global" one was the second, after
I realizedI had gotten the first one wrong.

Raoul Gough

unread,
Nov 8, 2002, 9:25:03 PM11/8/02
to
"Mark Charsley" <mark.charsley@REMOVE_THIS.radioscape.com> wrote in
message news:memo.2002110...@a.radioscape.com...

> In article <aq999t$k0n$1...@news.vol.cz>, c...@centrum.cz (Mirek Fidler)
> wrote:
>
> > If first Foo is aligned, than any other is aligned too. That
is
> > because
> > sizeof itself is aligned.
>
> <checks, looks surprised>
>
> Yup you're right. So given that calloc(x,y) can be implemented as
> malloc(x*y), does anyone know what purpose it serves?

I don't have the specification of calloc to hand, but maybe
calloc(1,64) is allowed to return single-byte aligned memory, whereas
malloc (64) probably isn't. Then again, I have a vague recollection
that they both return maximally-aligned memory all the time.

I often used to wonder about fread and fwrite having two size
parameters, and whether fwrite (&thing, 1, sizeof(thing), f) is ever
different to fwrite (&thing, sizeof(thing), 1, f). Maybe it's so
that you can handle numbers bigger than LONG_MAX, although
you probably won't get a successful calloc in that case :-)

Regards,
Raoul Gough.

Mark Heaps

unread,
Nov 11, 2002, 6:40:24 PM11/11/02
to
On 7 Nov 2002 20:56:23 -0500, mark.charsley@REMOVE_THIS.radioscape.com
(Mark Charsley) wrote:


>Yup you're right. So given that calloc(x,y) can be implemented as
>malloc(x*y), does anyone know what purpose it serves?
>

The contents of memory returned by calloc is initialized to 0. The
contents of memory allocated by malloc is indeterminate. So to
properly emulate calloc with malloc, you would also have to include a
memset(p, 0, x*y);
---
Mark Heaps mark dot a dot heaps at lmco dot com

0 new messages