Are these new placement macros correct?

I've made a couple of macros to make it easier to use the placement. I was just wondering if there were obvious cases where they would not work. Thank.

#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT)   ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE)         ((TYPE*)STORAGE)->~TYPE()

      

+2


source to share


5 answers


I'm not an expert on posting new ones, but there are a few issues with how you define a macro.

Problem 1

The most obvious problem is using cast (TYPE*)STORAGE

for storage location. This is not true. Placement new is another C ++ feature and it is involved in operations such as overload resolution. Dropping memory arbitrarily for a particular type can cause the new location to bind to a different new statement expected by the user.

For example, it is valid to have the following two placement definitions new. Your macro could potentially cause an incorrect call.

void * _cdecl operator new(size_t cbSize, void* pv);
void * _cdecl operator new(size_t cbSize, SomeType* pv)-

      

...



// These two call different overloads
void* p = malloc(sizeof(SomeType));
SomeType* f1 = CONSTRUCT_INPLACE(SomeType, p,()) 
SomeType* f2 = new (p) SomeType();

      

I wrote a blog post again about how you can use this type of overload resolution to implement custom allocators.

Problem 2

The STORAGE expression in a macro must be wrapped in parens to prevent errors in extension macros.

::new((TYPE*)(STORAGE)) TYPE INIT

      

+6


source


In addition to the questions asked elsewhere, your macros interact very poorly (i.e., not compile) with template types.

In general, macros should be avoided when there is no clear benefit. To be grossly honest, I don't see any real benefit here.



eg.

template< class A, class B >
class T
{
public:

    T(A y, B z) : x(y), w(z) {}
    A x;
    B w;
};

int main()
{
    void* p = ::operator new(sizeof(T));

    CONSTRUCT_INPLACE(T<int, double>, p, (4, 5.0));

    DESTRUCT_INPLACE(T<int, double>, p);

    ::operator delete(p);

    return 0;
}

      

+2


source


After looking at them, I wonder why the first casting (TYPE*)

is - for placement, new takes on the meaning void*

.

But again, I wonder if they are good for everyone. All they succeed is to further confuse what is not really trivial. Why do you think you need them?

Do you think you've looked at (admittedly several) standard libraries for working with uninitialized memory? (See the bottom half of this website. Perhaps you can use something.

+1


source


Yours CONSTRUCT_INPLACE

seems a little strange to me. Using:

void* p = <some memory location>;
Foo* f = CONSTRUCT_INPLACE(Foo, p, Foo())

// The macro-free version seems easier to read:
Foo* f = new(p) Foo();

      

DESTRUCT_INPLACE

is at least easier to read than the code it replaces.

But really, why are you posting so much new that these macros are useful to you? Put this in a pool class and forget about it.

0


source


The allocate-new operator creates an object in what is originally a block of "raw" memory. That is, the correct type of memory pointer passed to the new location is "void *". Casting it to type '(TYPE *)', like you, is safe, but useless. What is thrown into your "DESTRUCT" macro is also not immediately clear.

By the way, what's the point of having these macros at all? You say they "make the placement a little easier to use," but all they think is doing some totally unnecessary casts.

0


source







All Articles