Topic: is placement new[] really usable?


Author: xleobx@qmailcomq.com
Date: Thu, 23 May 2002 17:11:48 GMT
Raw View
Allan W <Allan_W@my-dejanews.com> wrote:

> Maybe the way to obtain the overhead quantity is:

>     namespace {
>         class get_oh_qty {};
>         size_t oh_qty;
>         // Here's a custom operator new
>         void*operator new(size_t arg, const get_oh_qty&)
>             // All it does is save the size that was requested
>             { oh_qty=arg; return 0; }
>     }; // namespace

>     size_t placement_new_overhead_quantity() {
>         operator new(1,get_oh_qty()); // Call custom operator new
>         // Return value includes padding bytes, if any,
>         // plus one extra byte for safety.
>         return oh_qty;
>     }

This will not do. This will:

size_t placement_new_overhead_quantity() {

        // Need to declare a dtor, otherwise the overhead may be 0
 // as there is no need to store elt count if there is no
 // need to call any dtors

        struct get_oh_qty { ~get_oh_qty() { } };
        const unsigned SAFETY_PAD = 2;
        double buf[sizeof(get_oh_qty)/sizeof(double) + SAFETY_PAD];
        get_oh_qty * p = new(buf) get_oh_qty[1];
        return (char*)p - (char*)buf;
}

And, unfortunately, there seems to be no way to form a placement delete expression.

 Leo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Thu, 23 May 2002 21:42:21 GMT
Raw View
Here's how to get the overhead, assuming that all forms
of array new require the same amount every time.

struct alloc
{
 size_t amt;
};

void *operator new[](size_t n, alloc &o) throw()
{
 o.amt = n;
 return 0;
}

template<typename T>
size_t overhead(size_t n)
{
 alloc a;
 ::new(a) T[n];
 return a.amt - n * sizeof(T);
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Allan_W@my-dejanews.com (Allan W)
Date: Wed, 22 May 2002 20:17:30 GMT
Raw View
Phil Brooks <phil_brooks@mentorg.com> wrote
> Is there a safe and portable way to correctly use placement new[]?
> I suspect that the answer lies in the footnote to 18.4.1.3 Placement forms:
>
> "The array new expression, may, however, increase the size argument
> to operator new[] (std::size_t) to obtain space to store
> supplemental information."
>
> The most intuitive (naive) use of placement new[] would be:
>
> mem = malloc( sizeof(A[100]) );
> a = new (mem) A[100];
>
> That usage will overwrite some unknown range of memory after the end
> of mem.  (I don't know what the non-naive usage is ...)

How about:
    mem = malloc(sizeof(a[100])+MAX_NEW_ARRAY_OVERHEAD);
    a = new(mem) A[100];
The value of MAX_NEW_ARRAY_OVERHEAD would, of course, be
implementation-specific -- for any given implementation, you might be
able to find the maximum amount documented, otherwise you could test
it by calling your own operator new[] under a variety of conditions,
comparing the size parameter to the original amount requested.

Alternatively, you could define MAX_NEW_ARRAY_OVERHEAD as 32. This
isn't guaranteed to work everywhere, but I suspect it will work
on almost all implementations with a huge margin of error. (The
actual amount used is more likely to be sizeof(long), which is
probably well under 32 bytes!)

> Otherwise, it seems that the standard should be amended to either
> mandate that there be no increase in the size argument in the case
> of placement new (this would be difficult to implement, would it
> not?) or that there be some simple and portable method of
> obtaining the overhead quantity for the array type in question.

Maybe the way to obtain the overhead quantity is:

    namespace {
        class get_oh_qty {};
        size_t oh_qty;
        // Here's a custom operator new
        void*operator new(size_t arg, const get_oh_qty&)
            // All it does is save the size that was requested
            { oh_qty=arg; return 0; }
    }; // namespace

    size_t placement_new_overhead_quantity() {
        operator new(1,get_oh_qty()); // Call custom operator new
        // Return value includes padding bytes, if any,
        // plus one extra byte for safety.
        return oh_qty;
    }

Here I'm assuming that the overhead quantity for that custom new is
equal to the overhead quantity for placement new. This isn't guaranteed --
in fact, the overhead quantity isn't guaranteed to be the same from one
call of placement new to the next! In practice I suspect it usually will
be, though.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Phil Brooks <phil_brooks@mentorg.com>
Date: Fri, 17 May 2002 17:28:14 GMT
Raw View
I posted this over on comp.lang.c++.moderated a while back and no one
has answered it.  The question is "Is there a safe and portable way to
correctly use placement new[]?" (complete posting below)

I suspect that the answer lies in the footnote to 18.4.1.3 Placement forms:

"The array new expression, may, however, increase the size argument to operator new[] (std::size_t)
to obtain space to store supplemental information."

(if anyone is keeping track of commas in the standard that need to be removed, the comma
after 'expression' above is incorrect)

If that is in fact the answer I would argue that placement new[] should be removed from the
language since it can not be used correctly.

The most intuitive (naive) use of placement new[] would be:

mem = malloc( sizeof(A[100]) );
a = new (mem) A[100];

That usage will overwrite some unknown range of memory after the end of mem.  (I
don't know what the non-naive usage is ...)

Otherwise, it seems that the standard should be amended to either mandate that there
be no increase in the size argument in the case of placement new (this would be
difficult to implement, would it not?) or that there be some simple and portable method of
obtaining the overhead quantity for the array type in question.

The first method would allow the naive implementation to work correctly at the
expense of making the compiler writer figure out if the new expression in question
is the real placement new or some other thing that just looks like placement new
and can actually allocate its own memory.

The second method would allow there to be a "here's right way to do it" caveat to be
added to the already lengthy "here's the right way to do it" C++ caveat list.

It seems the simplest thing is simply to remove placement new[] as a standard function
(or deprecate it or what ever).

Am I missing something?

Phil

<< previous posting to comp.lang.c++.moderated >>
How does one actually use placement new[]?

It seems that the user is missing a critical piece of data that is the size of
the array header used by new to mark the number of elements in the array.

Consider:

#include <new.h>
#include <stdlib.h>
#include <iostream.h>
using namespace std;

class C {
    public:
    C() { c = 0; }
    int c;
};

class A {
   public:
   A() { a = 0; }
   virtual ~A() {};
   virtual int get_data () const { return a; }
   int a;
};

int main()
{
   void* mem;
   A* a;

   mem = malloc( sizeof(A[100]) );
   cout << "mem=" << hex << mem << dec << endl;

   a = new (mem) A[100];
   cout << "a  =" << hex << a << dec << endl;
   a->~A();

   A* a1;

   a1 = new ((A*)mem) A[100];
   cout << "a1 =" << hex << a1 << dec << endl;
   a1->~A();

   C* c;
   c = new ((C*)mem) C[100];
   cout << "c  =" << hex << c << dec << endl;

   return(0);
}

I find that different compilers do different things here.  Particularly, the
value returned by new[] is sometimes shifted, presumably by the implementation
dependent amount necessary to squirrel away the number of objects in the array.
On g++, the type of the pointer passed in has an effect (i.e. void* doesn't get
adjusted, and A* does).

Here are outputs from various compilers:

Cygnus C++ 3.0:
mem=0x212d0
a  =0x212d0
a1 =0x212d8
c  =0x212d0

Sun Forte 6 compiler:
mem=62740
a  =62748
a1 =62748
c  =62740

Microsoft C++ .NET:
mem=0x002F2280
a  =0x002F2284
a1 =0x002F2284
c  =0x002F2280

HP aCC:
mem=0x40005538
a  =0x40005540
a1 =0x40005540
c  =0x40005540

So it seems to me that the placement array new function is entirely useless??

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "DrPizza" <peter@inkvine.fluff.org>
Date: Sat, 18 May 2002 19:35:15 GMT
Raw View
"Phil Brooks" <phil_brooks@mentorg.com> wrote in message
news:3CE5235D.81C493DA@mentor.com...
>
> I posted this over on comp.lang.c++.moderated a while back and no one
> has answered it.  The question is "Is there a safe and portable way to
> correctly use placement new[]?" (complete posting below)
>
> I suspect that the answer lies in the footnote to 18.4.1.3 Placement
forms:
>
> "The array new expression, may, however, increase the size argument to
operator new[] (std::size_t)
> to obtain space to store supplemental information."
>
> (if anyone is keeping track of commas in the standard that need to be
removed, the comma
> after 'expression' above is incorrect)
>
> If that is in fact the answer I would argue that placement new[] should be
removed from the
> language since it can not be used correctly.
>
> The most intuitive (naive) use of placement new[] would be:
>
> mem = malloc( sizeof(A[100]) );
> a = new (mem) A[100];
>

It strikes me that the obvious thing to do would be to say that placement
new must incur no such overhead.

The overhead is presumably permitted so that the implementation can, for
instance, prepend the array with the size of the array, or append the array
with a cookie so that it can test, upon deletion, for a write that has
exceeded the array bounds, or something of that nature.  This kind of thing
isn't appropriate for a placement new expression (placement new doesn't
allocate the memory, after all), so should be forbidden, if it isn't
already.  Thus, the above would be safe, as it would only attempt to write
to sizeof(A[100]) bytes.

--
peter@inkvine.fluff.org


umop ap!sdn



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]