Why the function with this signature
void* operator new (std::size_t size);
Cant be called in code like this
void* mem = new(100);
But rather it must be called like this
void mem = ::operator new(100);
Keyword new and operator new are different things.
Keyword new does:
Call operator new to allocate the memory. It can be overloaded for the type being allocated. Keyword new accepts optional arguments that get passed to operator new, this allows for placement new and non-throwing new syntax, see #include <new>.
Invoke the constructor of the object.
If the constructor throws, invoke the corresponding operator delete to free the memory. Note that if that operator delete is not accessible (not public), then new fails at compile time because operator delete cannot be called if the constructor throws and memory would be lost.
Keyword new cannot be overloaded, it always does these steps. This is operator new from step 1 what can be overloaded, normally along with operator delete from step 3.
In other words, X* p = new X(a, b, c); under the hood does something like (pseudo code):
X* p = static_cast<X*>(X::operator new(sizeof(X))); // 1. allocate memory
try {
p->X(a, b, c); // 2. invoke the constructor
}
catch(...) {
X::operator delete(p); // 3. free the memory if the constructor throw
throw;
}
In the above, if X does not overload its operator new, it is the global ::operator new that gets called. Note that X::operator new is implicitly static if overloaded.
There is a profound syntactical reason for this: placement new. With placement new, you can call a constructor without allocating memory for it. It's syntax is this:
#include <new>
Foo* foo = new(bufferPointer) Foo();
Obviously, part of this is the precise syntax you tried to call ::operator new()...
Related
I've seen a few places that show how to overload the global new function for allocations. What I would like to do is to have any call to 'new' call my function, which simply wraps the C++ standard 'operator new' and tracks memory usage. But I have a problem of not knowing how to construct the object because the type of the object is not available in the function:
void* operator new (std::size_t size)
{
// I don't know what to construct
}
struct MyClass{ int members[8];}
new MyClass; // I'd basically like to wrap the standard 'new' function allocator.
You are not supposed to construct an object inside of an overloaded operator new, only allocate raw memory of the requested size and return a pointer to it. The object’s constructor will be called on the returned memory after the operator new exits.
A new expression calls operator new specifying the size of the type, then calls the type’s constructor on that memory, and then returns a pointer to the object that was created.
Thus, an expression like new MyClass in your example is roughly equivalent (not exactly) to this:
//MyClass *cls = new MyClass;
void *mem = :: operator new (sizeof(MyClass));
MyClass *cls = static_cast<MyClass*>(mem);
cls->MyClass();
And the converse is true for the delete expression, which calls the type’s destructor, and then calls operator delete to deallocate the raw memory, eg:
//delete cls;
cls->~MyClass();
:: operator delete (cls);
It seems you're looking for a Factory function. A factory is a dedicated function (or even a class) that produced instances of a class.
E.g.
#include <memory>
struct MyClass { int members[8]; };
std::unique_ptr<MyClass> MyClassFactory() {
auto inst = std::make_unique<MyClass>();
// assign some stuff to members
return inst;
}
Basically, my question is whether the following code is valid.
void* mem = operator new(sizeof(T));
T* instance = new(mem) T;
delete instance;
If it isn’t, I’d be curious to know whether there is a way to split allocation and initialization for an object that is going to be deleted through delete obj;.
This does appear to be valid, as long as T is not an array type, and is not a class with a custom operator delete visible from its scope which is incompatible with the operator new you invoke.
[expr.delete]/2 says the operand of delete may be "a pointer to a non-array object created by a previous new-expression". The new-expression grammar syntax symbol does include the placement new syntax, and [expr.delete] doesn't say the previous new-expression needs to be a non-placement variety. And any new-expression including a placement new is considered to "create" an object.
The operator new allocation function and operator delete deallocation function involved do need to match up. operator new(sizeof(T)) will normally call the global ordinary allocation function, but to be more sure you can write ::operator new(sizeof(T)). The deallocation function is looked up in the scope of class T, so a static operator delete(void*); in a class could break this.
You might want to consider exception safety, though. A straight T* p = ::new T; is actually more equivalent to:
void* mem = ::operator new(sizeof(T));
T* p;
try {
p = ::new(mem) T;
} catch (...) {
::operator delete(mem, sizeof(T));
throw;
}
Your code is given almost exactly in the same form, as an explicit example, in the C++ standard:
21.6.2.3 Non-allocating forms [new.delete.placement]
void* operator new(std::size_t size, void* ptr) noexcept;
Returns: ptr.
Remarks: Intentionally performs no other action.
[ Example: This can be useful for constructing an object at a known
address:
void* place = operator new(sizeof(Something));
Something* p = new (place) Something();
— end example ]
Add a delete, after that, and you get what you wrote in your question.
If I do
struct MyStruct { ~MyStruct() { } };
void *buffer = operator new(1024);
MyStruct *p = new(buffer) MyStruct();
// ...
delete p; // <---------- is this okay?
is the delete guaranteed to take care of both calling ~MyStruct() as well as operator delete?
delete p is equivalent to
p->~MyStruct();
operator delete(p);
unless MyStruct has an alternative operator delete, so your example should be well-defined with the expected semantics.
[expr.delete]/2 states:
the value of the operand of delete may be ... a pointer to a non-array object created by a previous new-expression.
Placement new is a type of new-expression. [expr.new]/1:
new-expression:
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt
delete is defined to be a call to the destructor of the object and then a call to the deallocation function for the memory. [expr.delete]/6,7:
... the delete-expression will invoke the destructor (if any) for the object ...
... the delete-expression will call a deallocation function ...
As long as the deallocation function matches the allocation function (which it should, as long as you haven't overloaded operator delete for your class), then this should all be well defined.
[Revised] It's not generally OK, and you can only generally delete something that was obtained with the matching plain new expression. Otherwise it is up to you to guarantee that the deallocation function matches the allocation function (so using ::delete p; would be the safer general solution, assuming your original operator new was in the global namespace). In particular when the class in question (or one of its derived classes) overload operator new you have to be careful.
Since you're using a placement-new expression to create *p, and since there is no such thing as a "placement-delete expression", you have to destroy the object manually and then release the memory:
p->~MyStruct();
operator delete(buffer);
No, you should not generally call delete (in some cases like when operator delete is overleaded it may be ok).
char *buffer = new char[1024];
MyStruct *p = new(buffer) MyStruct(); //placement new "i'm just calling constructor"
p->~MyStruct(); //destroy the object.
//delete p; // WHAT? even if you override operator delete it may be opaque to reader.
delete [] buffer; // THIS DELETE IS OK (if you have first destroyed MyStruct)
void someCode()
{
char memory[sizeof(Foo)];
void* place = memory;
Foo* f = new(place) Foo();
}
and the signature of new placement operator
void * operator new(size_t, void *p)
{
return p;
}
I don't get how a constructor could be bind to void *p since a constructor doesn't return any values ?
EDIT:
the following code for instance doesn't compile :
struct A{};
void f(void * p)
{
}
int main()
{
f(A());
std::cin.ignore();
}
The problem here is that C++ new is confusing:
there is the operator new, which you can overload and is in charge of allocating raw memory
there is the new expression (such as new A(5)) which under the covers first call the corresponding operator new overload and then performs the construction
Note that you have no say as to how the construction is performed: you supplied the type and the constructor parameters, the language does the rest, and there is no way to change this behavior.
Therefore, when you overload/override operator new, you are only affecting the raw memory allocation. The full syntax of the new expression can clear things up:
new (somepointer) A(5)
^~~~~~~~~~~~~ ^~~~
The first part is the list of arguments passed to operator new, on top of the size of the object (always passed). The second part corresponds to the constructor call. If there is no parameter to be passed to new (apart from the size which you don't control) then the first part may be omitted yielding the typical form new A(5).
You are free to overload new as much as you want, for example:
new (alignof(A)) A(5);
will call an operator new overload accepting a size_t as supplementary argument (representing the necessary alignment for the type):
void* operator new(size_t size, size_t alignment);
note: the first argument (size) is always there.
So, placement new is just a fancy overload in its own right:
void* operator new(size_t, void* p) { return p; }
There is not much interest in such an operator (it does nothing), however it helps maintaining a consistent syntax and allows you a way to specify where to build an object via using the new expression so that it is not necessary to create another syntax to allow such operation.
Constructor called after operator new executed. You posted not equivalent code. Equvalent would be
struct A
{
constructor (void* this);
}
int main ()
{
A a = A::constructor(operator new ());
}
It is not c++, just pceudocode
I think that the source of your confusion is an assumption that new(place) Foo(); is a single operation; it is not. Here is what's going on:
A placement new operator is called to allocate memory
A constructor is called to initialize the allocated memory
The first call needs to return the value (a void*). It is a block of memory suitable to store your object. The second call is a constructor. It gets the value from the placement new operator as its hidden this parameter, and performs its regular initialization tasks on it.
I know that, new operator will call the constructor of class.
But how it's happening, what is ground level techniques used for this.
Here is how I imagine it:
T* the_new_operator(args)
{
void* memory = operator new(sizeof(T));
T* object;
try
{
object = new(memory) T(args); // (*)
}
catch (...)
{
operator delete(memory);
throw;
}
return object;
}
(*) Technically, it's not really calling placement-new, but as long as you don't overload that, the mental model works fine :)
It's not really the new operator that calls the constructor. It is more the compiler that translate the following line:
MyClass * mine = new MyClass();
Into the following:
MyClass * mine = malloc(sizeof(MyClass)); // Allocates memory
mine->MyClass(); // Calls constructor
With other error handling code that other answers have noted.
The compiler generates machine code for that. When the compiler sees
CSomeClass* object = new CSomeClass();
(new statement) it generates code that calls the appropriate operator new() (which allocates memory), calls the right constructor, calls destructors of all fully constructed subobjects in case of exception, calls operator delete() in case an exception occurs during construction. All this is done by extra machine code generated by the C++ compiler for that simply looking statement.