Issues with C++ 'new' operator? - c++

I've recently come across this rant.
I don't quite understand a few of the points mentioned in the article:
The author mentions the small annoyance of delete vs delete[], but seems to argue that it is actually necessary (for the compiler), without ever offering a solution. Did I miss something?
In the section 'Specialized allocators', in function f(), it seems the problems can be solved with replacing the allocations with: (omitting alignment)
// if you're going to the trouble to implement an entire Arena for memory,
// making an arena_ptr won't be much work. basically the same as an auto_ptr,
// except that it knows which arena to deallocate from when destructed.
arena_ptr<char> string(a); string.allocate(80);
// or: arena_ptr<char> string; string.allocate(a, 80);
arena_ptr<int> intp(a); intp.allocate();
// or: arena_ptr<int> intp; intp.allocate(a);
arena_ptr<foo> fp(a); fp.allocate();
// or: arena_ptr<foo>; fp.allocate(a);
// use templates in 'arena.allocate(...)' to determine that foo has
// a constructor which needs to be called. do something similar
// for destructors in '~arena_ptr()'.
In 'Dangers of overloading ::operator new[]', the author tries to do a new(p) obj[10]. Why not this instead (far less ambiguous):
obj *p = (obj *)special_malloc(sizeof(obj[10]));
for(int i = 0; i < 10; ++i, ++p)
new(p) obj;
'Debugging memory allocation in C++'. Can't argue here.
The entire article seems to revolve around classes with significant constructors and destructors located in a custom memory management scheme. While that could be useful, and I can't argue with it, it's pretty limited in commonality.
Basically, we have placement new and per-class allocators -- what problems can't be solved with these approaches?
Also, in case I'm just thick-skulled and crazy, in your ideal C++, what would replace operator new? Invent syntax as necessary -- what would be ideal, simply to help me understand these problems better.

Well, the ideal would probably be to not need delete of any kind. Have a garbage-collected environment, let the programmer avoid the whole problem.
The complaints in the rant seem to come down to
"I liked the way malloc does it"
"I don't like being forced to explicitly create objects of a known type"
He's right about the annoying fact that you have to implement both new and new[], but you're forced into that by Stroustrups' desire to maintain the core of C's semantics. Since you can't tell a pointer from an array, you have to tell the compiler yourself. You could fix that, but doing so would mean changing the semantics of the C part of the language radically; you could no longer make use of the identity
*(a+i) == a[i]
which would break a very large subset of all C code.
So, you could have a language which
implements a more complicated notion of an array, and eliminates the wonders of pointer arithmetic, implementing arrays with dope vectors or something similar.
is garbage collected, so you don't need your own delete discipline.
Which is to say, you could download Java. You could then extend that by changing the language so it
isn't strongly typed, so type checking the void * upcast is eliminated,
...but that means that you can write code that transforms a Foo into a Bar without the compiler seeing it. This would also enable ducktyping, if you want it.
The thing is, once you've done those things, you've got Python or Ruby with a C-ish syntax.
I've been writing C++ since Stroustrup sent out tapes of cfront 1.0; a lot of the history involved in C++ as it is now comes out of the desire to have an OO language that could fit into the C world. There were plenty of other, more satisfying, languages that came out around the same time, like Eiffel. C++ seems to have won. I suspect that it won because it could fit into the C world.

The rant, IMHO, is very misleading and it seems to me that the author does understand the finer details, it's just that he appears to want to mislead. IMHO, the key point that shows the flaw in argument is the following:
void* operator new(std::size_t size, void* ptr) throw();
The standard defines that the above function has the following properties:
Returns: ptr.
Notes: Intentionally performs no other action.
To restate that - this function intentionally performs no other action. This is very important, as it is the key to what placement new does: It is used to call the constructor for the object, and that's all it does. Notice explicitly that the size parameter is not even mentioned.
For those without time, to summarise my point: everything that 'malloc' does in C can be done in C++ using "::operator new". The only difference is that if you have non aggregate types, ie. types that need to have their destructors and constructors called, then you need to call those constructor and destructors. Such types do not explicitly exist in C, and so using the argument that "malloc does it better" is not valid. If you have a struct in 'C' that has a special "initializeMe" function which must be called with a corresponding "destroyMe" then all points made by the author apply equally to that struct as they do to a non-aggregate C++ struct.
Taking some of his points explicitly:
To implement multiple inheritance, the compiler must actually change the values of pointers during some casts. It can't know which value you eventually want when converting to a void * ... Thus, no ordinary function can perform the role of malloc in C++--there is no suitable return type.
This is not correct, again ::operator new performs the role of malloc:
class A1 { };
class A2 { };
class B : public A1, public A2 { };
void foo () {
void * v = ::operator new (sizeof (B));
B * b = new (v) B(); // Placement new calls the constructor for B.
delete v;
v = ::operator new (sizeof(int));
int * i = reinterpret_cast <int*> (v);
delete v'
}
As I mention above, we need placement new to call the constructor for B. In the case of 'i' we can cast from void* to int* without a problem, although again using placement new would improve type checking.
Another point he makes is about alignment requirements:
Memory returned by new char[...] will not necessarily meet the alignment requirements of a struct intlist.
The standard under 3.7.3.1/2 says:
The pointer returned shall be suitably aligned so that it can be converted to a
pointer of any complete object type and then used to access the object or array in the storage allocated (until
the storage is explicitly deallocated by a call to a corresponding deallocation function).
That to me appears pretty clear.
Under specialized allocators the author describes potential problems that you might have, eg. you need to use the allocator as an argument to any types which allocate memory themselves and the constructed objects will need to have their destructors called explicitly. Again, how is this different to passing the allocator object through to an "initalizeMe" call for a C struct?
Regarding calling the destructor, in C++ you can easily create a special kind of smart pointer, let's call it "placement_pointer" which we can define to call the destructor explicitly when it goes out of scope. As a result we could have:
template <typename T>
class placement_pointer {
// ...
~placement_pointer() {
if (*count == 0) {
m_b->~T();
}
}
// ...
T * m_b;
};
void
f ()
{
arena a;
// ...
foo *fp = new (a) foo; // must be destroyed
// ...
fp->~foo ();
placement_pointer<foo> pfp = new (a) foo; // automatically !!destructed!!
// ...
}
The last point I want to comment on is the following:
g++ comes with a "placement" operator new[] defined as follows:
inline void *
operator new[](size_t, void *place)
{
return place;
}
As noted above, not just implemented this way - but it is required to be so by the standard.
Let obj be a class with a destructor. Suppose you have sizeof (obj[10]) bytes of memory somewhere and would like to construct 10 objects of type obj at that location. (C++ defines sizeof (obj[10]) to be 10 * sizeof (obj).) Can you do so with this placement operator new[]? For example, the following code would seem to do so:
obj *
f ()
{
void *p = special_malloc (sizeof (obj[10]));
return new (p) obj[10]; // Serious trouble...
}
Unfortunately, this code is incorrect. In general, there is no guarantee that the size_t argument passed to operator new[] really corresponds to the size of the array being allocated.
But as he highlights by supplying the definition, the size argument is not used in the allocation function. The allocation function does nothing - and so the only affect of the above placement expression is to call the constructor for the 10 array elements as you would expect.
There are other issues with this code, but not the one the author listed.

Related

Initializing an array of trivially_copyable but not default_constructible objects from bytes. Confusion in [intro.object]

We are initializing (large) arrays of trivially_copiable objects from secondary storage, and questions such as this or this leaves us with little confidence in our implemented approach.
Below is a minimal example to try to illustrate the "worrying" parts in the code.
Please also find it on Godbolt.
Example
Let's have a trivially_copyable but not default_constructible user type:
struct Foo
{
Foo(double a, double b) :
alpha{a},
beta{b}
{}
double alpha;
double beta;
};
Trusting cppreference:
Objects of trivially-copyable types that are not potentially-overlapping subobjects are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read().
Now, we want to read a binary file into an dynamic array of Foo. Since Foo is not default constructible, we cannot simply:
std::unique_ptr<Foo[]> invalid{new Foo[dynamicSize]}; // Error, no default ctor
Alternative (A)
Using uninitialized unsigned char array as storage.
std::unique_ptr<unsigned char[]> storage{
new unsigned char[dynamicSize * sizeof(Foo)] };
input.read(reinterpret_cast<char *>(storage.get()), dynamicSize * sizeof(Foo));
std::cout << reinterpret_cast<Foo *>(storage.get())[index].alpha << "\n";
Is there an UB because object of actual type Foo are never explicitly created in storage?
Alternative (B)
The storage is explicitly typed as an array of Foo.
std::unique_ptr<Foo[]> storage{
static_cast<Foo *>(::operator new[](dynamicSize * sizeof(Foo))) };
input.read(reinterpret_cast<char *>(storage.get()), dynamicSize * sizeof(Foo));
std::cout << storage[index].alpha << "\n";
This alternative was inspired by this post. Yet, is it better defined? It seems there are still no explicit creation of object of type Foo.
It is notably getting rid of the reinterpret_cast when accessing the Foo data member (this cast might have violated the Type Aliasing rule).
Overall Questions
Are any of these alternatives defined by the standard? Are they actually different?
If not, is there a correct way to implement this (without first initializing all Foo instances to values that will be discarded immediately after)
Is there any difference in undefined behaviours between versions of the C++ standard?
(In particular, please see this comment with regard to C++20)
What you're trying to do ultimately is create an array of some type T by memcpying bytes from elsewhere without default constructing the Ts in the array first.
Pre-C++20 cannot do this without provoking UB at some point.
The problem ultimately comes down to [intro.object]/1, which defines the ways objects get created:
An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]).
If you have a pointer of type T*, but no T object has been created in that address, you can't just pretend that the pointer points to an actual T. You have to cause that T to come into being, and that requires doing one of the above operations. And the only available one for your purposes is the new-expression, which requires that the T is default constructible.
If you want to memcpy into such objects, they must exist first. So you have to create them. And for arrays of such objects, that means they need to be default constructible.
So if it is at all possible, you need a (likely defaulted) default constructor.
In C++20, certain operations can implicitly create objects (provoking "implicit object creation" or IOC). IOC only works on implicit lifetime types, which for classes:
A class S is an implicit-lifetime class if it is an aggregate or has at least one trivial eligible constructor and a trivial, non-deleted destructor.
Your class qualifies, as it has a trivial copy constructor (which is "eligible") and a trivial destructor.
If you create an array of byte-wise types (unsigned char, std::byte, or char), this is said to "implicitly create objects" in that storage. This property also applies to the memory returned by malloc and operator new. This means that if you do certain kinds of undefined behavior to pointers to that storage, the system will automatically create objects (at the point where the array was created) that would make that behavior well-defined.
So if you allocate such storage, cast a pointer to it to a T*, and then start using it as though it pointed to a T, the system will automatically create Ts in that storage, so long as it was appropriately aligned.
Therefore, your alternative A works just fine:
When you apply [index] to your casted pointer, C++ will retroactively create an array of Foo in that storage. That is, because you used the memory like an array of Foo exists there, C++20 will make an array of Foo exist there, exactly as if you had created it back at the new unsigned char statement.
However, alternative B will not work as is. You did not use new[] Foo to create the array, so you cannot use delete[] Foo to delete it. You can still use unique_ptr, but you'll have to create a deleter that explicitly calls operator delete on the pointer:
struct mem_delete
{
template<typename T>
void operator(T *ptr)
{
::operator delete[](ptr);
}
};
std::unique_ptr<Foo[], mem_delete> storage{
static_cast<Foo *>(::operator new[](dynamicSize * sizeof(Foo))) };
input.read(reinterpret_cast<char *>(storage.get()), dynamicSize * sizeof(Foo));
std::cout << storage[index].alpha << "\n";
Again, storage[index] creates an array of T as if it were created at the time the memory was allocated.
My first question is: What are you trying to achieve?
Is there an issue with reading each entry individually?
Are you assuming that your code will speed up by reading an array?
Is latency really a factor?
Why can't you just add a default constructor to the class?
Why can't you enhance input.read() to read directly into an array? See std::extent_v<T>
Assuming the constraints you defined, I would start with writing it the simple way, reading one entry at a time, and benchmark it.
Having said that, that which you describe is a common paradigm and, yes, can break a lot of rules.
C++ is very (overly) cautious about things like alignment which can be issues on certain platforms and non-issues on others. This is only "undefined behaviour" because no cross-platform guarantees can be given by the C++ standard itself, even though many techniques work perfectly well in practice.
The textbook way to do this is to create an empty buffer and memcpy into a proper object, but as your input is serialised (potentially by another system), there isn't actually a guarantee that the padding and alignment will match the memory layout which the local compiler determined for the sequence so you would still have to do this one item at a time.
My advice is to write a unit-test to ensure that there are no issues and potentially embed that into the code as a static assertion. The technique you described breaks some C++ rules but that doesn't mean it's breaking, for example, x86 rules.
Alternative (A): Accessing a —non-static— member of an object before its lifetime begins.
The behavior of the program is undefined (See: [basic.life]).
Alternative (B): Implicit call to the implicitly deleted default constructor.
The program is ill-formed (See: [class.default.ctor]).
I'm not sure about the latter. If someone more knowledgeable knows if/why this is UB please correct me.
You can manage the memory yourself, and then return a unique_ptr which uses a custom deleter. Since you can't use new[], you can't use the plain version of unique_ptr<T[]> and you need to manually call the destructor and deleter using an allocator.
template <class Allocator = std::allocator<Foo>>
struct FooDeleter : private Allocator {
using pointer = typename std::allocator_traits<Allocator>::pointer;
explicit FooDeleter(const Allocator &alloc, len) : Allocator(alloc), len(len) {}
void operator()(pointer p) {
for (pointer i = p; i != p + len; ++i) {
Allocator::destruct(i);
}
Allocator::deallocate(p, len);
}
size_t len;
};
std::unique_ptr<Foo[], FooDeleter<>> create(size_t len) {
std::allocator<Foo> alloc;
Foo *p = nullptr, *i = nullptr;
try {
p = alloc.allocate(len);
for (i = p; i != p + len; ++i) {
alloc.construct(i , 1.0f, 2.0f);
}
} catch (...) {
while (i > p) {
alloc.destruct(i--);
}
if (p)
alloc.deallocate(p);
throw;
}
return std::unique_ptr<Foo[], FooDeleter<>>{p, FooDeleter<>(alloc, len)};
}

c++ string in C struct, is it illegal?

struct run_male_walker_struct {
string male_user_name;
string show_name;
};
typedef struct run_male_walker_struct run_male_walker_struct_t;
in another function:
run_male_walker_struct_t *p = malloc(sizeof(struct run_male_walker_struct));
question, is it illegal? As the string is a class, it's size can't be determined by sizeof().
This is illegal, but not for the reasons you're thinking.
The difference between std::malloc()/std::free() and new/delete is that the latter will call constructors/destructors, while the former won't. The expression
void* p = std::malloc(sizeof(run_male_walker_struct))
will return a blob of uninitialized memory on which no constructor is called. You shouldn't touch it with a ten foot pole - except for invoking a constructor on it:
run_male_walker_struct* pw = new(p) run_male_walker_struct;
If you do this, you will have to do the reverse, too:
pw->~run_male_walker_struct();
before you free the memory:
std::free(p);
However, that leaves the question why you want to do that.
The only reason to do this should be when you want to separate memory allocation from construction (like, for example, in a pool allocator). But if you need that, it's best hidden behind some interface. A natural one would be overloading new and delete per class. Also, std::vector does this internally.
Not really sure what you're asking here... Just to be clear, the struct keyword is a valid C++ designation, that functions nearly identically to class except for the default privacy. So if you're compiling with g++, and including the string library, this is a valid statement.
However, calling with malloc() will just give you the memory, not actually construct the values inside that struct. You could more appropriately instantiate it by calling it's default constructor.
The struct definition itself is fine. It results is a non-POD aggregate. But you should prefer the use of new and delete over malloc and free because these handle construction and destruction properly. If you want to keep using malloc and free you have to use the placement-new to properly construct the object and invoke the destructor manually to destroy it before you free it:
#include <new>
...
run_male_walker_struct *p = (run_male_walker_struct*)
malloc(sizeof(run_male_walker_struct));
new(p) run_male_walker_struct; // <-- placement-new
...
p->~run_male_walker_struct(); // <-- pseudo destructor call
free(p);
Or simply:
run_male_walker_struct *p = new run_male_walker_struct;
...
delete p;
BTW: the typedef is not necessary in C++
Try not to use malloc, if you are in C++.
Using NEW is a better alternative, when you browse into the NEW() code, you will realize it does call malloc!!!
The pros of using NEW is it will call the constructor of your class instantiated.
Another minor comment, the code you provided should not be compilable:
run_male_walker_struct_t *p = malloc(sizeof(struct run_male_walker_struct));
Should be
run_male_walker_struct_t *p = (run_male_walker_struct_t*)malloc(sizeof(struct run_male_walker_struct));
this is due to malloc will return a void*.
Using malloc() would work, but using it will only create enough space for your struct.
This means that you will not be able to use your strings properly, because they weren't initialised with their constructors.
Note that string classes don't have their contents in stack memory, but in dynamic memory, which doesn't affect the size of the struct. All classes and structs have a static size, that are known at compile-time (if the struct/class was defined).
I would suggest using new. Using malloc will stuff up the strings.
This raises a question of my own, how did constructors get called on dynamically allocated instantiation in C (were there no such things as constructors in C?). If so, yet another reason against using pure C.
How about
run_male_walker_struct_t * p = new run_male_walker_struct_t:
I'm fairly sure this is legal because the size of the std::string object will be known even if the lengths of the strings are not known. The results may not be what you expect though because malloc won't call constructors.
Try this:
std::string testString1("babab");
std::string testString2("12345678");
std::string testString3;
std::cout <<" sizeof(testString1)" <<sizeof(testString1) << std::endl;
std::cout <<" sizeof(testString2)" <<sizeof(testString2) << std::endl;
std::cout <<" sizeof(testString3)" <<sizeof(testString3) << std::endl;
On my machine this gives me the following output:
sizeof(testString1)8
sizeof(testString2)8
sizeof(testString3)8
Also is there some reason you are not using:
run_male_walker_struct_t *p = new(struct run_male_walker_struct);
This is the correct way to do it in c++, using malloc is almost certainly a mistake.
EDIT: see this page for a more detailed explanation of new vs malloc in c++:
http://www.codeproject.com/KB/tips/newandmalloc.aspx
The answer depends on what you mean by a "C struct".
If you mean "a struct that is valid under the C language", then the answer is obviously: it contains a datatype that isn't valid C, and so the struct itself isn't valid either.
If you mean a C++ POD type, then the answer is no, it is not illegal, but the struct is no longer a POD type (because in order to be POD, all its members must be POD as well, and std::string isn't)

Size of class instance

I'm working with a class for which the new operator has been made private, so that the only way to get an instance is to write
Foo foo = Foo()
Writing
Foo* foo = new Foo()
does not work.
But because I really want a pointer to it, I simulate that with the following :
Foo* foo = (Foo*)malloc(sizeof(Foo));
*foo = Foo();
so that can test whether the pointer is null to know whether is has already been initialized.
It looks like it works, from empirical tests, but is it possible that not enough space had been allocated by malloc ? Or that something else gets funny ?
--- edit ---
A didn't mention the context because I was not actually sure about why they the new operator was disabled. This class is part of a constraint programming library (gecode), and I thought it may be disabled in order to enforced the documented way of specifying a model.
I didn't know about the Concrete Data Type idiom, which looks like a more plausible reason.
That allocation scheme may be fine when specifying a standard model --- in which everything is specified as CDTs in the Space-derived class --- but in my case, these instance are each created by specific classes and then passed by reference to the constructor of the class that reprensents the model.
About the reason i'm not using the
Foo f;
Foo *pf = &f;
it would be like doing case 1 below, which throws a "returning reference to local variable" warning
int& f() { int a=5; return a; } // case 1
int& f() { int a=5; int* ap=&a; return *ap; }
int& f() { int* ap=(int*)malloc(sizeof(int)); *ap=5; return *ap; }
this warning disappears when adding a pointer in case 2, but I guess it is because the compiler loses tracks.
So the only option left is case 3 (not mentioning that additionaly, ap is a member of a class that will be initialized only once when f is called, will be null otherwise, and is the only function returning a reference to it. That way, I am sure that ap in this case when lose its meaning because of the compilier optimizing it away (may that happen ?)
But I guess this reaches far too much beyond the scope of the original question now...
Don't use malloc with C++ classes. malloc is different from new in the very important respect that new calls the class' constructor, but malloc does not.
You can get a pointer in a couple ways, but first ask yourself why? Are you trying to dynamically allocate the object? Are you trying to pass pointers around to other functions?
If you're passing pointers around, you may be better off passing references instead:
void DoSomething(Foo& my_foo)
{
my_foo.do_it();
}
If you really need a pointer (maybe because you can't change the implementation of DoSomething), then you can simply take the pointer to an automatic:
Foo foo;
DoSomething(&foo);
If you need to dynamically allocate the Foo object, things get a little trickier. Someone made the new operation private for a reason. Probably a very good reason. There may be a factory method on Foo like:
class Foo
{
public:
static Foo* MakeFoo();
private:
};
..in which case you should call that. Otherwise you're going to have to edit the implementation of Foo itself, and that might not be easy or a good thing to do.
Be careful about breaking the Concrete Data Type idiom.
You are trying to circumvent the fact that the new operator has been made private, i.e. the Concrete Data Type idiom/pattern. The new operator was probably made private for specific reasons, e.g. another part of the design may depend on this restriction. Trying to get around this to dynamically allocate an instance of the class is trying to circumvent the design and may cause other problems or other unexpected behavior. I wouldn't suggest trying to circumvent this without studying the code thoroughly to ensure you understand the impact to other parts of the class/code.
Concrete Data Type
http://users.rcn.com/jcoplien/Patterns/C++Idioms/EuroPLoP98.html#ConcreteDataType
Solutions
...
Objects that represent abstractions that live "inside" the program, closely tied to the computational model, the implementation, or the programming language, should be declared as local (automatic or static) instances or as member instances. Collection classes (string, list, set) are examples of this kind of abstraction (though they may use heap data, they themselves are not heap objects). They are concrete data types--they aren't "abstract," but are as concrete as int and double.
class ScopedLock
{
private:
static void * operator new (unsigned int size); // Disallow dynamic allocation
static void * operator new (unsigned int size, void * mem); // Disallow placement new as well.
};
int main (void)
{
ScopedLock s; // Allowed
ScopedLock * sl = new ScopedLock (); // Standard new and nothrow new are not allowed.
void * buf = ::operator new (sizeof (ScopedLock));
ScopedLock * s2 = new(buf) ScopedLock; // Placement new is also not allowed
}
ScopedLock object can't be allocated dynamically with standard uses of new operator, nothrow new, and the placement new.
The funny thing that would happen results from the constructor not being called for *foo. It will only work if it is a POD (simple built-in types for members + no constructor). Otherwise, when using assignment, it may not work out right, if the left-hand side is not already a valid instance of the class.
It seems, you can still validly allocate an instance on the heap with
Foo* p = ::new Foo;
To restrict how a class instance can be created, you will probably be better off declaring the constructor(s) private and only allow factory functions call them.
Wrap it:
struct FooHolder {
Foo foo;
operator Foo*() { return &foo; }
};
I don't have full understanding of the underlying code. If other things are ok, the code above is correct. Enough space will be allocated from malloc() and anything funny will not happen. But avoid using strange code and work straighforward:
Foo f;
Foo *pf = &f;

Are these placement new macros correct?

I made a couple macros to make using placement new a bit easier. I was just wondering if there were any obvious cases where these would not work. Thanks.
#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT) ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE) ((TYPE*)STORAGE)->~TYPE()
I'm not an expert in placement new but there are a couple of issues with how you are defining the macro.
Issue 1
The most obvious problem is the use of the cast (TYPE*)STORAGE for the storage location. This is incorrect. Placement new is just another C++ function and it participates in operations like overload resolution. Arbitrarily casting the memory to a specific type could cause the placement new to bind to a different operator new that the user expected.
For example, it's valid to have the following two definitions of placement new. Your macro would potentially cause the wrong one to be called.
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 awhile back on how you can use this type of overload resolution to implement custom allocators.
http://blogs.msdn.com/jaredpar/archive/2007/10/17/c-placement-new-and-allocators.aspx
Issue 2
The expression STORAGE in the macro should be wrapped in parens to prevent evil macro expansion bugs.
::new((TYPE*)(STORAGE)) TYPE INIT
In addition to issues stated elsewhere your macros interact very badly (i.e. fail to compile) with template types.
In general, macros should be avoided when there is no clear benefit. To be brutally honest, I can't see a real benefit here.
e.g.
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;
}
Looking at them, I wonder what that first (TYPE*) cast is for - placement new takes a void*, after all.
But then again, I wonder what they are good for at all. All they manage is to further obfuscate something that isn't really trivial to begin with. Why do you think you need them?
That being said, have you looked at the (admittedly few) standard library facilities for dealing with uninitialized memory? (See the lower half of this website. There might be something you can use.
Your CONSTRUCT_INPLACE seems a bit odd to me. Usage would be:
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 doing so much placement new that these macros are of use to you? Put that stuff in a pool class and forget about it.
Placement-new operator creates an object in what initially is a block of "raw" memory. I.e. the proper type for the memory pointer passed to the placement new is 'void*'. Casting it to type '(TYPE*)', as you do, is harmless, but useless. What is the point of the cast in your 'DESTRUCT' macro is also not immediately clear.
BTW, what is the point of having these macros at all? You say they "make using placement new a bit easier", but all they seem to do is perform some completely unnecessary casts.

Can assignment be done before constructor is called?

A comment to What's wrong with this fix for double checked locking? says:
The issue is that the variable may be
assigned before the constructor is run
(or completes), not before the object
is allocated.
Let us consider code:
A *a;
void Test()
{
a = new A;
}
To allow for more formal analysis, let us split the a = new A into several operations:
void *mem = malloc(sizeof(A)); // Allocation
new(mem) A; // Constructor
a = reinterpret_cast<A *>(mem); // Assignment
Is the comment quoted above true, and if it is, in what sense? Can Constructor be executed after the Assignment? If it can, what can be done against it when guaranteed order is needed because of MT safety?
The issue isn't so much when code executes, but more to do with write-ordering.
Let's suppose:
A()
{
member = 7;
}
Then later:
singleton = new A()
This results in code that does an allocation, a write to memory (member), and then a write to another memory location (singleton). Some CPU's can re-order writes such that the write to member will not be visible until after the write to singleton - in essence, code running on other CPU's in the system could have a view of memory where singleton is written to, but member is not.
I think following should work:
void Test()
{
A *temp = new A;
MemoryWriteBarrier(); // use whatever memory barrier your platform offers
a = temp;
}
a is a global object with static storage duration so it's going to be initialised in some pre-allocated storage sometime before the body of main get executed. Assuming that a call to Test isn't the result of some static object construction weirdness, a will be full constructed by the time Test is called.
a = new A;
This slightly unusual assignment isn't going to be (only) a standard copy assignment operation as you are assigning a pointer to A to a, not an object or reference. Whether it actually compiles and what exactly it calls depends on whether A has an assignment operator that takes a pointer to A, or something implicitly convertable from a pointer to A or whether A has an non-explicit constructor that takes a pointer to A (or a pointer to a base class of A).
Post edit, your code does something rather different!
Conceptually, it does something more like this:
A *tmpa;
void *mem = ::operator new( sizeof(A) ); // ( or possibly A::operator new )
try
{
tmpa = new (mem) A; // placement new = default constructor call
}
catch (...)
{
::operator delete( mem );
throw;
}
a = tmpa; // pointer assignment won't throw.
The peril with writing something out like this is that your implicitly adding a lot of sequence points that just aren't there in the original, and in addition the compiler is allowed to generate code that doesn't look like this so long as it behaves 'as if' it were written by this as far as the executing program could determine. This 'as if' rule only applies to the executing thread as the (current) language says nothing about interaction with other threads works.
For this you need to use the specific behaviour guarantees (if any) proided by your implementation.
Yes, the constructor can be called after the assignment, although the example you gave is not internally consistent (As noted by a comment on it).
You can throw in some locks for peace of mind, but it's easy to get that wrong, too.
see
"C++ and the Perils of Double-Checked Locking"
by Scott Meyers and Andrei Alexandrescu
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf