operator new and new operator, which can't be overloaded? - c++

It seems both can be overloaded, but somebody said not.....
What's the case?

It seems you are making the distinction between the handling of new-expressions and allocation functions. new-expressions call constructors in addition for class types and is responsible for looking up allocation functions (so it is built into the compiler) and calling them. You can't change that behavior. What you can change is the behavior of allocation functions. Their name is operator new and they are found and used by new-expressions to allocate memory.
See Plain new, new[], delete and delete[] in a nutshell.

You can overload all four of, new, new[], delete, and delete[]. See section 13.5 of the standard.

You can overlload new operator but you cannot define new operators(like ^ or ++).
If it is not what you meant please clarify.

Related

The c++ programming language by Bjarne Stroustrup - operator new

Section "11.2.4 Overloading new" ends with:
"There is no special syntax for placement of arrays. Nor need there be since arbitrary types can be allocated by placement new. However, an operator delete can be defined for arrays".
If I understand it correctly, what is being said is that for arrays, we use the usual placement new syntax, which would invoke the appropriate operator new[]. But, what I don't understand is the last sentence. What is he trying to say there? Afaik, we can specify both operator new and operator delete for arrays.
There is a special allocator for arrays (operator new[]()) but it is not dependent on a special syntax.
In the following code
new T();
or
new (p) T();
The compiler will generate a call to either operator new(...) or operator new[](...) depending on whether T is an array type. There is no syntactic difference in the new-expression.
(Now, there is a special syntax for a new-expression with a runtime size... but invocation of operator new[]() is not limited to scenarios with a runtime size)
In contrast to new, for delete the same pointer type is compatible with both scalar and array. So you the programmer must tell the compiler which you want via
delete p;
vs
delete [] p;
There is no automatic translation to delete[] based on recognition of an array type.

Overloading new and delete, what's with new[] and delete[]?

A very short question, but surprisingly I didn't find anything on the web:
I'm overloading new and delete for a class. Do I also need to overload new[] and delete[] or will they automatically "redirect" to the overloaded new and delete?
I assume you are talking about class-specific overloading, not replacing the global operators new and delete(which should be avoided unless really needed).
Anyway, to answer your question, No- they don't automatically redirect. You have to specifically overload operators that you need. new and new[] are two different operators.
No it will not automatically do any forwarding. operator new and operator new[] do different things.

What are the limitations of overloading, overriding and replacing new/delete?

I understand that there are 3 general ways to modify the behaviour of new and delete in C++:
Replacing the default new/delete and new[]/delete[]
Overriding or overloading the placement versions (overriding the one with a memory location passed to it, overloading when creating versions which pass other types or numbers of arguments)
Overloading class specific versions.
What are the restrictions for performing these modifications to the behaviour of new/delete?
In particular are there limitations on the signatures that new and delete can be used with?
It makes sense if any replacement versions must have the same signature (otherwise they wouldn't be replacement or would break other code, like the STL for example), but is it permissible to have global placement or class specific versions return smart pointers or some custom handle for example?
First off, don't confuse the new/delete expression with the operator new() function.
The expression is a language construct that performs construction and destruction. The operator is an ordinary function that performs memory (de)allocation.
Only the default operators (operator new(size_t) and operator delete(void *) can be used with the default new and delete expressions. All other forms are summarily called "placement" forms, and for those you can only use new, but you have to destroy objects manually by invoking the destructor. Placement forms are of rather limited and specialised need. By far the most useful placement form is global placement-new, ::new (addr) T, but the behavior of that cannot even be changed (which is presumably why it's the only popular one).
All new operators must return void *. These allocation functions are far more low-level than you might appreciate, so basically you "will know when you need to mess with them".
To repeat: C++ separates the notions of object construction and memory allocation. All you can do is provide alternative implementations for the latter.
When you overload new and delete within a class you are effectively modifying the way the memory is allocated and released for the class, asking for it to give you this control.
This may be done when a class wants to use some kind of pool to allocate its instances, either for optimisation or for tracking purposes.
Restrictions, as with pretty much any operator overload, is the parameter list you may pass, and the behaviour it is expected to adhere to.

Why does c++ have its separate syntax for new & delete?

Why can't it just be regular function calls? New is essentially:
malloc(sizeof(Foo));
Foo::Foo();
While delete is
Foo:~Foo();
free(...);
So why does new/delete end up having it's own syntax rather than being regular functions?
Here's a stab at it:
The new operator calls the operator new() function. Similarly, the delete operator calls the operator delete() function (and similarly for the array versions).
So why is this? Because the user is allowed to override operator new() but not the new operator (which is a keyword). You override operator new() (and delete) to define your own allocator, however, you are not responsible (or allowed to for that matter) for calling appropriate constructors and destructors. These function are called automatically by the compiler when it sees the new keyword.
Without this dichotomy, a user could override the operator new() function, but the compiler would still have to treat this as a special function and call the appropriate constructor(s) for the object(s) being created.
You can overload operator new and operator delete to provide your own allocation semantics. This is useful when you want to bypass the default heap allocator's behavior. For example if you allocate and deallocate a lot of instances of a small, fixed-size object, you may want to use a pool allocator for its memory management.
Having new and delete as explicit operators like other operators makes this flexibility easier to express using C++'s operator overloading mechanism.
For auto objects on the stack, allocation/constructor call and deallocation/destructor calls basically are transparent as you request. :)
'Cause there is no way to provide complie-time type safety with a function (malloc() returns void*, remember). Additionally, C++ tries to eliminate even a slightest chance of allocated but uninitialized objects floating around. And there are objects out there without a default constructor - for these, how would you feed constructor arguments to a function? A function like this would require too much of a special-case handling; easier to promote it to a language feature. Thus operator new.
'new/delete' are keywords in the C++ language (like 'for' and 'while'), whereas malloc/calloc are function calls in the standard C library (like 'printf' and 'sleep'). Very different beasts, more than their similar syntax may let on.
The primary difference is that 'new' and 'delete' trigger additional user code - specifically, constructors and destructors. All malloc does is set aside some memory for you to use. When setting aside memory for a simple plain old data (floats or ints, for example), 'new' and 'malloc' behave very similarly. But when you ask for space for a class, the 'new' keyword sets aside memory and then calls a constructor to initialize that class. Big difference.
Why does C++ have separate syntax for greater-than? Why can't it just be a regular function call?
greaterThan(foo, bar);

STL allocators and operator new[]

Are there STL implementations that use operator new[] as an allocator? On my compiler, making Foo::operator new[] private did not prevent me from creating a vector<Foo>... is that behavior guaranteed by anything?
C++ Standard, section 20.4.1.1. The default allocator allocate() function uses global operator new:
pointer allocate(size_type n, allocator<void>::const_pointerhint=0);
3 Notes: Uses ::operator new(size_t) (18.4.1).
std library implementations won't use T::operator new[] for std::allocator. Most of them use their own memory pooling infrastructure behind the scenes.
In general, if you want to stop Foo objects being dynamically allocated, you'll have to have make all the constructors private and provide a function that creates Foo objects. Of course, you won't be able to create them as auto variables either though.
std::vector uses an Allocator that's passed as a template argument, which defaults to std::allocate. The allocator doesn't work like new[] though -- it just allocates raw memory, and placement new is used to actually create the objects in that memory when you tell it to add the objects (e.g. with push_back() or resize()).
About the only way you could use new[] in an allocator would be if you abused things a bit, and allocated raw space using something like new char[size];. As abuses go, that one's fairly harmless, but it's still unrelated to your overload of new[] for the class.
If you want to prohibit the creation of your object make private constructor rather than operator new.
In addition to the other answers here, if you want to prevent anyone from creating a STL container for your type Foo, then simply make the copy-constructor for Foo private (also the move-constructor if you're working with C++11). All STL-container objects must have a valid copy or move constructor for the container's allocator to properly call placement new and construct a copy of the object in the allocated memory block for the container.