placement new and delete

Discussion in 'C++' started by LuB, Jun 17, 2007.

  1. LuB

    LuB Guest

    I am constantly creating and destroying a singular object used within
    a class I wrote.

    To save a bit of time, I am considering using 'placement new'. I guess
    we could also debate this decision - but for the sake of this post ...
    I'm searching for an answer that assumes said decision.

    If I allocate memory in the class declaration:

    char buffer[sizeof(ObjectX)];

    and use 'placement new' inside of of an instance' method:

    pObjectX = new (buffer) ObjectX;

    then, when it comes time to clean up, I understand that I must
    explicitly invoke the destructor .... but its not clear to me if I
    need to use placement delete at all?

    pObjectX->~ObjectX();
    operator delete (pObjectX_, buffer); // ?????? is this or some
    version of this required? or more-safe?

    Especially considering, I am just going to create the object again and
    again ... and I'm not relinquishing control of the memory space back
    to the OS. ctor, dtor, ctor, dtor ... just not sure what delete does
    in this case.

    I guess I'm just not sure what operator delete (arg1, arg2) does? and
    if its required when using placement new.

    Thanks in advance,

    -Luther
     
    LuB, Jun 17, 2007
    #1
    1. Advertisements

  2. LuB

    James Kanze Guest

    My first question would be: how will it save time?
    You likely get undefined behavior. You have to do something to
    ensure that buffer is correctly aligned.
    I'm not sure what you're even trying to do here.
    If you don't call it, it doesn't do anything.
    It gets called if the constructor in a placement new throws an
    exception.
    *If* you have a placement new which actually allocates new
    resources, you should provide a corresponding placement delete.
    If in a new expression which uses your placement new function,
    the constructor of the object exits with an exception, the
    compiler will call your placement delete.

    That's the only time it can or will be called.
     
    James Kanze, Jun 17, 2007
    #2
    1. Advertisements

  3. LuB

    Ian Collins Guest

    Have you considered giving the object its own new and delete operators?
     
    Ian Collins, Jun 17, 2007
    #3
  4. Make sure you use the right alignment.
    long buffer[ (sizeof(ObjectX)+sizeof(long)-1)/sizeof(long) ];
    ..... that's it - do no more.
    Don't so this ..
    Whatever it is, it's probably not what you want to do.

    operator new and operator delete concern themselves with memory allocation.

    When using operator now - like so:

    new T();

    It will allocate memory using operator new and then run the constructor
    (like placement new).
     
    Gianni Mariani, Jun 18, 2007
    #4
  5. LuB

    Alan Johnson Guest

    How does that ensure correct alignment?
     
    Alan Johnson, Jun 18, 2007
    #5
  6. LuB

    James Kanze Guest

    It doesn't, at least not on a Sun Sparc compiling in 32 bit
    mode (and probably on a lot of other machines where long is 32
    bits, and double 64).

    The usual solution is to use a union:

    union MaxAlign {
    int i ;
    long l ;
    long double ld ;
    double d ;
    void* p ;
    void (* pf)() ;
    MaxAlign* ps ;
    } ;
    union {
    char data[ sizeof( ObjectX ) ] ;
    MaxAlign dummyForAlignment ;
    } buffer;

    new ( buffer.data ) ...

    Technically, even that isn't guaranteed by the standard, but in
    practice, it should work. (Logically, you shouldn't need double
    if you have long double, but I've encountered cases where long
    double has an alignment of 4, and double an alignment of 8.)

    This may result in allocating too much memory for small types.
    There are template meta-programming tricks which can be used to
    avoid this, if it is a problem.
     
    James Kanze, Jun 18, 2007
    #6
  7. LuB

    Pete Becker Guest

    Looking forward, the next revision of the standard incorporates TR1's
    templates alignment_of and aligned_storage, as well as the alignof
    keyword. With TR1, you'd write:

    aligned_storage<sizeof(ObjectX),
    alignment_of<ObjectX>::value>::type data;
    ObjectX *ptr = new(&data) ObjectX;

    With C++0x the same thing still works, but you can be a little less
    verbose with:

    aligned_storage<sizeof(ObjectX), alignof(ObjectX)>::type data;
    ObjectX *ptr = new(&data) ObjectX;

    or, if you want the compiler to figure out the optimal alignment:

    aligned_storage<sizeof(ObjectX)>::type data;
    ObjectX *ptr = new(&data) ObjectX;

    --

    -- Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com)
    Author of "The Standard C++ Library Extensions: a Tutorial and
    Reference." (www.petebecker.com/tr1book)
     
    Pete Becker, Jun 18, 2007
    #7
  8. LuB

    JohnQ Guest

    He'll have to call the delete operator explicitely in his code somewhere to
    get any behavior defined in the class's destructor. Use of placement delete
    should be used symmetrically with placement new.

    John
     
    JohnQ, Jun 19, 2007
    #8
  9. LuB

    JohnQ Guest

    That's explicitely calling the destructor.
    This is placement new's syntax:
    This is placement delete's syntax (Or so, how I categorize it. It's just an
    explicit call to the destructor. I'm not sure if the standard actually
    defines placement deleta as some internal call or not. Probably. The below
    is the companion behavior to placement new.):
    There's no requirement to overload the class's new and/or delete operators
    to use placement syntax.

    John
     
    JohnQ, Jun 19, 2007
    #9
  10. LuB

    LuB Guest


    It doesn't allocate memory. It essentially just returns a pointer.

    Not sure I follow but then, maybe my example wasn't clear.

    struct ObjectX { int x; int y; };

    struct UserAnObject
    {
    char buffer[sizeof(ObjectX)];

    void onMouseDown()
    {
    pObjectX = new (buffer) ObjectX;

    // do something here

    }

    void onCaptureChanged()
    {
    // finish doing something here

    pObjectX->~ObjectX();
    operator delete (pObjectX_, buffer);
    }

    ObjectX* pOBjectX;

    };


    See above for clarification.


    No. My example does not.

    Not sure how it will call 'my placement delete' unless you're
    referring to a class member. My example does not define a 'placement
    delete'. I am wondering if I should invoke the global placement
    delete ... (hope that makes sense).
    Thanks for your initial input ... hopefully, my comments make things a
    little clearer?

    Thanks,

    -Luther
     
    LuB, Jun 19, 2007
    #10
  11. Pete Becker wrote:
    ....
    How does the proposal define "optimal" alignment?
     
    Gianni Mariani, Jun 19, 2007
    #11
  12. LuB

    James Kanze Guest

    [Hey, this one worked. Now I'll have to go back and figure
    out where I posted it from:).]

    I'm not too sure what you mean by "call the delete operator
    explicitely", but placement new and placement delete are not
    symmetrical. Placement new is called by means of a new
    expression; there is no way to invoke placement delete by means
    of a delete expression, which always uses a non-placement
    delete.

    The most frequent use of placement delete is when separating
    memory management and construction/deletion, in e.g. a container
    class. This uses the standard placement delete, the one with
    the void* argument. And you never call delete on such objects,
    you call the destructor explicitly.

    In the case of user defined placement new which do require a
    delete, e.g. when the argument is the address of a special
    allocator or pool, you also have to redefine the non-placement
    operator new and operator delete functions, and arrange somehow
    in the non-placement operator delete function to handle the
    special cases.
     
    James Kanze, Jun 19, 2007
    #12
  13. LuB

    James Kanze Guest

    The memory has to be allocated somehow, in every case. You
    can't construct an object without having the memory for it.

    I had more or less assumed that the memory would be declared as
    as local variable. In which case, the comparison isn't with
    non-placement delete, but with just declaring a local instance
    of the object.
    If you've declared buffer as a local (or a static) object:
    char buffer[ sizeof( ObjectX ) ] ;
    you're not at all guaranteed that it will be correctly aligned
    for an ObjectX; on my system, if very often won't be.
    And where is UserAnObject declared? In this case (a bit
    special), you're garanteed that the buffer has the same address
    as the whole object (but only because UserAnObject is a
    POD---add a constructor, for example, and you loose the
    guarantee), but this doesn't necessarily mean that it is
    sufficiently aligned for an ObjectX. Again, on my system, when
    compiling in 32 bit mode, the compiler will ensure that all
    UserAnObject are aligned on an address multiple of 4, because
    this is necessary for the pointer it contains, but if ObjectX
    contains a double, it requires an alignment on a multiple of 8.

    If UserAnObject in fact contains virtual functions, the compiler
    will insert the vptr before "char buffer[]", almost guaranteeing
    that it will NOT be correctly aligned for a double if
    UserAnObject is dynamically allocated.

    Also: you don't really have to call operator delete here. The
    standard guarantees that it is a no-op, but in general, if the
    operator new called by the new expression doesn't allocate any
    resources, you don't need to call operator delete.
    OK. It's not necessary, and it's not usual to see it (although
    the standard guarantees that it will work).

    [...]
    For the standard placement new and delete, there's really never
    any reason to call placement delete. For a user defined one,
    however...

    Consider something like:

    union BlockHeader { Allocator* alloc, double forAlignment } ;

    void*
    operator new( size_t n, Allocator* pAlloc )
    {
    BlockHeader* p =
    static_cast< BlockHeader* >(
    pAlloc->alloc( n + sizeof( BlockHeader ) ) ;
    if ( p == NULL ) {
    throw std::bad_alloc() ;
    }
    p->alloc = pAlloc ;
    return p + 1 ;
    }

    void*
    operator new( size_t n )
    {
    BlockHeader* p =
    static_cast< BlockHeader* >( malloc( n +
    sizeof( BlockHeader ) ) ;
    if ( p == NULL ) {
    throw std::bad_alloc() ;
    }
    p->alloc = NULL ;
    return p + 1 ;
    }

    void
    operator delete( void* userPtr )
    {
    BlockHeader* p
    = static_cast< BlockHeader* >( userPtr ) - 1 ;
    if ( p->alloc == NULL ) {
    free( p ) ;
    } else {
    p->alloc->free( p ) ;
    }
    }

    According to the rules, if you do something like:

    MyType* p = new ( someAllocator ) MyType ;

    and the constructor of MyType exits via an exception, no
    operator delete function will be called. If you have a
    corresponding placement delete, however, it will be called.
    Since in this case, you are actually allocating memory in your
    placement new, you should provide a placement delete, so that it
    will be called.
     
    James Kanze, Jun 19, 2007
    #13
  14. LuB

    JohnQ Guest

    " [Hey, this one worked. Now I'll have to go back and figure
    out where I posted it from:).]"

    (No it didn't. Because the post was so short, I put the '>' symbols in by
    hand. Notice they're missing the usual space after the symbols.)

    "I'm not too sure what you mean by "call the delete operator
    explicitely",

    SomeClassObjectPtr->~SomeClassObject()

    " but placement new and placement delete are not
    symmetrical. Placement new is called by means of a new
    expression; there is no way to invoke placement delete by means
    of a delete expression, which always uses a non-placement
    delete."

    I'm probably using the terminology "placement delete" wrong. But it would
    seem fitting in my context because placement new is object construction and
    the above explicit call of the class delete is object destruction. I
    understand that there is a delete operator with a void* argument hidden
    somewhere (internal to the compiler?). Why object construction was
    obfuscated in the placement new syntax befuddles me.

    "The most frequent use of placement delete is when separating
    memory management and construction/deletion, in e.g. a container
    class. This uses the standard placement delete, the one with
    the void* argument. And you never call delete on such objects,
    you call the destructor explicitly."

    Define "standard placement delete" please.

    "In the case of user defined placement new which do require a
    delete, e.g. when the argument is the address of a special
    allocator or pool, you also have to redefine the non-placement
    operator new and operator delete functions, and arrange somehow
    in the non-placement operator delete function to handle the
    special cases."

    Define "user defined placement new" please. I don't understand how that can
    be useful. So it can be redefined? What good would that do since the
    mechanics of calling constructors is not exposed? When I think of placement
    new, I think of the syntax that engages the behavior (construction), not the
    actual implementation of placement new.

    John
     
    JohnQ, Jun 19, 2007
    #14
  15. LuB

    LuB Guest

    Thanks for the extended response. Everyone's responses have been quite
    helpful.

    So I'm taking a step back. Many people avoid certain idioms like the
    plague ... such as using memset as a fast, cheap way to copy entire
    objects, etc. It just opens up lots of potentially unwanted behavior
    or conditions.

    So - on a slightly deeper or higher level, what about this 'approach'?
    We've talked about explicitly invoking the delete operator - but
    underneath that ... is placement new a good option in this situation?

    I could change the object architecture a little bit -- and edit my
    class to have build and destroy functionality in methods ... instead
    of ctor and dtor pairs - and I could just allocate said object with
    the instance ... and explicitly objectX.build(...) and
    objectX.destroy(...) the same object over and over again ... if that
    approach would be better than using placement new.

    I guess, I understand that I can't guarantee alignment ... and, I know
    that were I writing Assembly, that means I'd have to go out of my way
    to read the data ... but what does that mean in a normal compiler? I
    thought the compiler would hide things like that from me. Does it mean
    things will be slower than optimal? or does that mean things will
    break? or does that mean things are undefined on different OSs or with
    different compilers? Admittedly, its not a commonly used idiom (I
    guess) and while I guess things like alignment might not be guaranteed
    - I'm not sure what that means - in terms of "Go For It" ... but
    realize it'll be problematic ..? or stay away from it - since you open
    a bag of worms.

    I didn't hear alot of negative reaction ... but then again, we were
    focussed on the need to explicitly invoke the delete operator or not.
    It seems like a good approach ... Allows me to Initialize in ctor and
    Destroy in dtor (traditional OO) -- and its only one object (easy to
    manage) ... so 'new' and 'delete' work well in general for my
    situation ... but this idea of placement new ... is it really a good
    optimization in this context?

    For what its worth, the implementation doesn't really _have_ to be
    portable. It is part of a proprietary windowing system ... but I'd
    like it to be relatively safe, predictable, reliable and faster than
    constantly allocating and releasing memory to the OS many times.

    Thanks to all,

    -Luther
     
    LuB, Jun 20, 2007
    #15
  16. LuB

    James Kanze Guest

    [...]
    Maybe. Over all, I'd probably favor a pointer and classical
    new, until the profiler said that allocation really was a
    bottleneck. It has the advantage of being a simple, easy to
    understand way of doing things.
    If you're always building the same type, just adding a
    reinitialize function to it would seem to be the best solution.
    It does when it knows about them. If you declare an ObjectX,
    the compiler will assure that it is adequately aligned. The
    problem here is that you are declaring a char[]; the compiler
    will ensure that it is adequately aligned for a char[], but that
    might not be enough for an ObjectX.
    It's basically undefined or unspecified behavior. On an Intel
    architecture, it means that things will be slower. On a Sparc
    (and most other architectures I've seen), it means that the
    program will core dump. It's quite possible that on some
    architecture, you simply get wrong values, or end up modifying
    something outside the object when you meant to change a value in
    the object.
    You open a bag of worms. I've done similar things once or twice
    in the past, when the profiler said they were needed, but you
    generally have to be very, very careful.
    If you take the necessary steps to ensure correct alignment,
    there's no reason why it can't be made to work. As I said, I've
    done so in the past. But it is additional complexity for
    nothing unless you really need it.
    Operator delete doesn't necessarily (or even usually) release
    memory to the OS. Most of the time, it allocates from and frees
    to an arena which it maintains itself, only going to the OS when
    it doesn't have enough memory otherwise. If you're dealing with
    fixed size objects, it's also fairly simple to implement your
    own allocator, to reuse the previously deleted object.
     
    James Kanze, Jun 20, 2007
    #16
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.