Thread: Placement new?

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654

    Placement new?

    OK, so next step is to use placement new. I'm not sure on how to use it. I've never done it before.
    I've done a very simple test to get the hang of it:

    Code:
    void* __cdecl operator new(std::size_t size, LPCSTR strLine, int nLine)
    {
    	//::operator new(size, strLine, nLine);
    	New::CMemoryRange* p = (New::CMemoryRange*)VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    	new (p) New::CMemoryRange;
    	return 0;
    }
    Initiated by:

    Code:
    new New::CMemoryRange;
    Is this the right way to use placement new? Because all I get is:

    Code:
    inline void *__CRTDECL operator new(size_t, void *_Where)
            {return (_Where); }
    In essence, it does nothing but return the same argument I passed in!

    The basic idea here is to allocate memory using VirtualAlloc, then use placement new to actually construct the object, but I'm not sure how to do it.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The default placement new does exactly that, yeah. But other placement new forms can do different things.

    What you want is a pool allocator. That's different from placement new.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Then how do I go about constructing the object once it's allocated?
    Using templates to deduce the correct type and call the constructor is obviously out of question since that would generate a different new...
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I'm not sure I understand. If you have a pointer to some memory, you can use the normal placement new to create an object there.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    But how do I do it?
    How do I fix the above code sample to work? How do I make new construct the object and call the constructor?
    As I mentioned, I don't really know how placement new works. Never used it before.
    If it's placement new or whatever else method, I care not, but somehow the constructor must be called so that objects are properly constructed. Simply allocating memory won't do.

    On a side note, there is only one delete, one that calls the destructor and frees the memory?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The function you override, operator new(), is responsible only for allocating memory. Actually calling the constructor when the new operator is used is the compiler's business.

    I suggest you look into Stroustrup's C++ Programming Language or Meyers's Effective C++ series to really learn how the new operator and operator new work and interact.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ah, books. Great learning resources they are... if you can find them somewhere locally, that is.
    But yes, you're right of course... the compiler will call the constructor after the call to operator new.
    Hmmm. It might just be possible to get this show on the road!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    that isn't overriding placement new, it's overriding New::CMemoryRange::operator new. so for example:

    Code:
    #include <cstdlib>
    #include <iostream>
     
    using namespace std;
     
    struct test
    {
        test( void )
        {
            cout << "test( ) at address " << ( int * )this << endl;
        }
    
        static
        void *
        allocate( size_t size )
        {
            void * address = malloc( size );
            cout << "allocating " << size << " bytes at address " << ( int * )address << endl;
            return address;
        }
     
        static
        void *
        operator new( size_t size )
        {
            return allocate( size );
        }
    
        static
        void *
        operator new[ ]( size_t size )
        {
            return allocate( size );
        }
    
        static
        void
        deallocate( void * address )
        {
            cout << "deallocating at address " << ( int * )address << endl;
            free( address );
        }
    
        static
        void
        operator delete( void * address )
        {
            deallocate( address );
        }
     
        static
        void
        operator delete[ ]( void * address )
        {
            deallocate( address );
        }
    
        ~test( void )
        {
            cout << "~test( ) at address " << ( int * )this << endl;
        }
     
        char buffer[ 1024 ];
    };
     
    int
    main( void )
    {
        delete [ ] new test[ 4 ];
    }
    [edit]
    added code to account for arrays. also, I may be wrong about whether this is in fact overloading placement new. I'll look into it...
    [/edit]
    Last edited by Sebastiani; 02-25-2008 at 08:19 PM. Reason: revisions, clarifications
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I'm not sure if this is completely accurate, but it should be pretty close...

    Code:
    #include <cstdlib>
    #include <iostream>
     
    using namespace std;
     
    /*
        wrappers for invoking constructors and
        destructors 'in place' on raw memory
    */
     
    template < typename Type >
    inline
    Type &
    constructor( Type & object )
    {
        return *new( &object ) Type( );
    }
     
    template < typename Type >
    inline
    Type &
    constructor( Type & object, Type const & value )
    {
        return *new( &object ) Type( value );
    }
     
    template < typename Type >
    inline
    Type *
    constructor( Type * array, size_t size )
    {
        return new( array ) Type[ size ];
    }
     
    template < typename Type >
    inline
    void
    destructor( Type & object )
    {
        object.~Type( );
    }
     
    template < typename Type >
    inline
    void
    destructor( Type * array, size_t size )
    {
        for( size_t index = 0; index < size; index++ )
            destructor( array[ index ] );
    }
     
    /*
        overriding class-specific new/delete
        note: these *must* not throw exceptions
    */
     
    struct special
    {
        special( void )
        {
            cout << "special::special( ) at address " << ( int * )this << endl;
        }
     
        static
        void *
        allocate( size_t size )
        {
            void * address = malloc( size );
            cout << "special::allocate " << size << " bytes at address " << ( int * )address << endl;
            return address;
        }
     
        static
        void *
        operator new( size_t size )
        {
            return allocate( size );
        }
     
        static
        void *
        operator new[ ]( size_t size )
        {
            return allocate( size );
        }
    /*
        new/new[] for 'in place' construction. note: the second parameter
        can be overloaded for special types (such as pool allocators)
    */
        static
        void *
        operator new( size_t size, special * address )
        {
            cout << "(in place) special::operator new[ ] at address " << ( int * )address << endl;
            return address;
        }
     
        static
        void *
        operator new[ ]( size_t size, special * address )
        {
        /*
            the compiler seems to think we need extra bytes
            for book keeping, as if we were allocating memory
            (why??). is this a portable approach?
        */
            size_t const array_book_keeping_bytes = 4;
            cout << "(in place) special::operator new[ ] at address " << ( int * )address << endl;
            return ( char * )address - array_book_keeping_bytes;
        }
     
        static
        void
        deallocate( void * address )
        {
            cout << "special::deallocate at address " << ( int * )address << endl;
            free( address );
        }
     
        static
        void
        operator delete( void * address )
        {
            deallocate( address );
        }
     
        static
        void
        operator delete[ ]( void * address )
        {
            deallocate( address );
        }
     
        ~special( void )
        {
            cout << "special::~special( ) at address " << ( int * )this << endl;
        }
     
        char buffer[ 1024 ];
    };
     
    struct standard
    {
        standard( void )
        {
            cout << "standard::standard( ) at address " << ( int * )this << endl;
        }
     
        ~standard( void )
        {
            cout << "standard::~standard( ) at address " << ( int * )this << endl;
        }
     
        char buffer[ 1024 ];
    };
     
    /*
        overriding global new/delete
    */
     
    void *
    allocate( size_t size ) throw( std::bad_alloc )
    {
        void * address = malloc( size );
        if( address == 0 )
            throw std::bad_alloc( );
        cout << "global allocate " << size << " bytes at address " << ( int * )address << endl;
        return address;
    }
     
    void *
    operator new( size_t size ) throw( std::bad_alloc )
    {
        return allocate( size );
    }
     
    void *
    operator new[ ]( size_t size ) throw( std::bad_alloc )
    {
        return allocate( size );
    }
     
    template < typename Type >
    void *
    operator new( size_t size, Type * address )
    {
        cout << "(in place) global operator new[ ] at address " << ( int * )address << endl;
        return address;
    }
     
    template < typename Type >
    void *
    operator new[ ]( size_t size, Type * address )
    {
        size_t const array_book_keeping_bytes = 4;
        cout << "(in place) global operator new[ ] at address " << ( int * )address << endl;
        return ( char * )address - array_book_keeping_bytes;
    }
     
    void
    deallocate( void * address )
    {
        cout << "global deallocate at address " << ( int * )address << endl;
        free( address );
    }
     
    void
    operator delete( void * address )
    {
        deallocate( address );
    }
     
    void
    operator delete[ ]( void * address )
    {
        deallocate( address );
    }
     
    int
    main( void )
    {
        size_t const elements = 4;
    /*
        use class-specific memory management
    */
        delete [ ] new special[ elements ];
    /*
        use 'in place' constructor/destructor
    */
        char special_buffer[ sizeof( special ) * elements ];
        constructor( ( special * )special_buffer, elements );
        destructor( ( special * )special_buffer, elements );
    /*
        use global memory management
    */
        delete [ ] new standard[ elements ];
    /*
        use 'in place' constructor/destructor
    */
        char standard_buffer[ sizeof( standard ) * elements ];
        constructor( ( standard * )standard_buffer, elements );
        destructor( ( standard * )standard_buffer, elements );
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Thanks for the tip, but as CornedBee mentioned, the compiler will call the constructor/destructor for me, so I was wrong in that I needed to call placement new.
    And I'm overriding global new and delete, as well, not inside a namespace.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Curly Brace Placement
    By sean in forum General Discussions
    Replies: 96
    Last Post: 06-16-2009, 10:08 PM
  2. My Placement come true
    By vasanth in forum A Brief History of Cprogramming.com
    Replies: 3
    Last Post: 06-07-2004, 06:07 AM
  3. Placement..
    By vasanth in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 03-01-2004, 10:21 PM
  4. placement of (.h) and (.cpp) files..!?
    By matheo917 in forum C++ Programming
    Replies: 3
    Last Post: 02-22-2003, 06:37 PM
  5. CIOS college placement tests
    By compjinx in forum A Brief History of Cprogramming.com
    Replies: 2
    Last Post: 12-13-2002, 02:33 AM