operator new[] definition breakdown - c++

I am having hard time digesting this syntax:
void* operator new[](std::size_t, const std::nothrow_t&) throw();
while this is still understood:
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
Question:
I thought new and subscript [] are different operators. how can we combine two operators to overload in one definition?
Also the nowthrow. The following call doesnt make sense to me ( with respect to the signature of the function ).
int * p2 = new (nothrow) int;
If anyone can give reference to related topics from bjarne stroustrup's book that would be great, not a hard requirement though.
UPDATE: Please try to answer both questions :)

new[] and [] are two completely different operators.
new[] is an allocation operator for arrays, [] is a subscript access operator for arrays.
new[] is it's own operator, it's not simply 'new' allocator combined with '[]' subscript operator.

The first two are the signatures of the global new operators. For what (little) it's worth, operator new is used to allocate space for a new expression like x = new T;, while operator new[] is used to allocate space for a new expression like x = new T[count];. The "little" that it's worth is for a fairly simple reason: you should never use new T[count], so how it works is almost purely a historical curiosity.
You can overload ::operator new and/or ::operator new[] to provide your own heap allocation if you want to. There's no difference between the two as far as basic requirements go -- they both just allocate and return a pointer to the amount of memory requested.
As far as nothrow goes, the size that gets passed to operator new is always computed by the compiler based on the size of the object and in the case of an array new the count you give. Therefore, the parameter you specify in the new expression turns into the second parameter that's passed to operator new.
To emphasize a point I may not have made quite clearly enough above: operator new (and operator new[]) are used by, but separate from new expressions (what you have in your code when you say something like x = new T;). operator new and operator new[] are pretty much like malloc -- they just allocate "raw" memory. A new expression1 uses one of those to allocate raw memory, then invokes the constructor to allocate an object (or more than one, in the case of new T[count];) in that memory. The two are obviously related, but equally obviously not really the same.
One other minor point: it's also possible to have an operator new (or operator new[] as a class member. This allows you to allocate memory differently for that class than for others that use the global heap. This tends to be most common with small objects that you expect to allocate in large numbers. For these, the global heap often has quite a lot of overhead that you'd prefer to avoid.
Finally, when/if you want to allocate raw memory, you can also invoke operator new directly, as in void *a = ::operator new(1234);. About the only place this is common is if you decide to implement some sort of collection class on your own (e.g., if you want a circular buffer).

new and new[] are two separate operators, not really related to the '[]' operator.
This is best seen on the difference between delete p and delete[] p; are you deleting a single instance pointed to by p, or a whole array of instances?
Likewise, new[] is a way to allocate a whole array of objects, all in the same memory block.

Related

Placement-new vs new-expression

Again with placement new I've found an example on this forum like this:
char *buf = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi"); // placement new
string *q = new string("hi"); // ordinary heap allocation
But I think here buf is a pointer to an allocated and Constructed dynamic array of default-init characters. So the characters in the array are default initialized and have an indeterminate values.
I guess using the placement new in the second line will constructs objects on the previously constructed array of objects.
Why the user didn't call operator new on the array allocation rather than using new expression?:
char *buf = static_cast<char*>(operator new[](sizeof(string)));
After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.
Are my guesses correct?
Here is the link to the original answer:
What uses are there for "placement new"?
Why the user didn't call operator new on the array allocation rather than using new expression?:
We cannot answer that question because we aren't that user. You should ask that from the user - though given that the example was written in 1998 it might not be easy to contact them. My guess: They didn't know that non-placement operator new exists or they didn't know what it is used for. Reusing the memory of an array of char is an intuitive choice in such case.
Note that the example of creating a singular dynamic std::string object makes little sense in the first place (I'm assuming that's what string in the example is).
I have a similar question to you: Why are you using operator new[] in your suggestion and not operator new? Even more importantly, why not use an allocator?
Are my guesses correct?
Correct.
Correct.
This is a question and not a guess. I covered it above.
It would fail. But that's irrelevant since char is default constructible.
char is an object type that is both fundamental and trivial. Creating one doesn't, in practice, touch memory, and making an array of them does not either.
char* foo = new char[10];
and
char *foo = static_cast<char*>(operator new[](10));
end up doing exactly the same thing in machine code, except the second one is a lot more verbose.
There are some subtle differences in the abstract machine; in one a bunch of chars are created, in the other the other they are not on that line. Coming up with a case where that matters is going to require a fair bit of language lawyering effort (I am thinking disposal may be different, and some access might be different, especially in standard versions before c++ fixed the malloc problem).
After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.
Sure, but the cast would be code smell, and the point of buf is to be storage for the later placement new. I guess it already is,
void *foo = operator new[](10);
is less bonkers.
Just because you can static cast does not mean you should.
operator new[](sizeof(string)) that's something odd, its incorrect syntax for creating an object. In best case scenario it creates an object in memory implicitly (if operator new implemented as std::malloc call and object is a POD type), without initializing or constructing one. All you can do in that case is to static_cast<char*>(new string); The offered line just would create a string object in dynamic storage and then make it anonymous by replacing type of pointer by char*.
Thing is, for placement new buf is not necessary to point to dynamic memory. It can be a static buffer.It can be a pointer to memory location within a rather large storage used to store multiple objects, a memory pool. New object would constructed at given location.
Note that in case of placement new std::string's data storage is still behaves as it usually does - it allocates character data in dynamic memory. To use some memory pool, programmer should provide appropriate allocator and that's one of purposes for placement new operator.
No, buf isn't an array of objects. It's an array of characters, so basically an array of bytes. And while it was allocated with an array new, its basically being used as a byte pointer.
The use of placement new is if you want to allocate an object at an exact location, but you want to do so following all the rules of C++ object allocation- so constructors called and vtables set up. The usual use case for this is if you're doing your own custom memory allocation and reusing existing memory addresses. Firmware may use this to reuse memory as a pool. Or an RTOS may use it so that it doesn't exceed memory restrictions for a task.
This is actually a poor example of how its used because of that. You'd never new an array then placement new into it. You'd have a pointer to a block of allocated memory lying around, and you'd use placement new into that.

Delete for placement or non-placement new

Does anyone know a C++ delete procedure that is safe for both placement new and for regular new?
Object* regular = new Object();
delete_procedure(regular);
void* buf = ::new(sizeof(Object));
Object* placement = new(buf) Object();
delete_procedure(placement);
This function seems to work, but I can't figure out if it's actually safe for both instances (it's the standard method of deleting placement new).
delete_procedure(Object* obj){ // Not sure if safe for regular new
obj->~Object();
::delete(obj);
}
I don't believe there's any unified way of doing this without introducing some extra flags to mark things. The C++ philosophy is "you need to keep track of how you allocated things and ensure they're all destroyed properly," and it does this for efficiency purposes. Think about delete[] versus delete. There could be a unified delete keyword that cleans up any block of memory, but that would incur a performance overhead because of the cost of determining which deallocation routine needs to be invoked. Or think about virtual destructors: C++ could say that delete always does some kind of type introspection, but that would add overhead to all object types, much of it unnecessarily.
C++'s philosophy is "don't pay for what you don't use," and so if you want to build something unified, you'll need to set up some extra infrastructure to track what sorts of deletion routine you need to do.
No, because of arrays and details. Sure, because these problems probably don't matter in your code base.
All deletes are either type specific deletes, or:
The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new(size_t) or operator new(size_t, std::nothrow_t).
from http://en.cppreference.com/w/cpp/memory/new/operator_delete
This means passing memory allocated by new[](size_t) to delete(void*) is UB, and new[](size_t) to delete[](void*) is UB.
Second, users are free to replace new/delete on a global or per-class basis.
Third:
void delete_procedure(Object* obj){
obj->~Object();
::operator delete((void*)obj);
}
you'll want to cast to void pointer there and use operator delete.
Forth, the pointer passed to delete_procedure must be the pointer generated by new T or ::new( ::new(sizeof(T)) ) T; it cannot be a pointer to a derives subobject, as its value as a void* may differ.
If T* pt is dynamic castable, dynamic_cast<void*>( pt ) will reconstruct that void*. So this is less of a barrier than it seems. Remember to do the cast before destroying the object!
void delete_procedure_dynamic(Object* obj){
void* ptr=dynamic_cast<void*>(obj);
obj->~Object();
::operator delete(ptr);
}
and use SFINAE/tag dispatching to dispatch between the dynamic and non-dynamic versions.
Fifth, high alignment types need work to handle. They use different new and delete. I am uncertain how dynamic casting and over aligned derived types would interact, but probably you don't have to care.
But new T calls ::new(size_t)`` then constructs an object there.operator delete(void*)must be fed memory produced by::new(size_t). Destroying an object creates bynew Tis legal via.~T()`. So I see nothing fundamentally broken.
In practice, what I might do is override "normal" new to follow the same pattern as your extra storage new (and allocate the block via new(size_t)) to keep things simple. You are in arcane territory, why not make things uniform.

Putting restrictions in overloading new and delete

Is it possible to put some restrictions in overloading operators new and delete?
My overloaded new is linked in a different file to my test program.
The scenario is:
if(condition is satisfied)
call overloaded new
else
call the actual new defined in new.h
Always use your overloaded new/delete and check your condition inside its implementation.
Once you replace the default ::operator new() you can't use it anymore - it's gone forever. See this question.
If you want to have the effect of the original ::operator new() you'll have to reimplement it which isn't very hard.
There are three ways to provide an operator new.
replacing one or more of the four non placement default operators new,
providing overload to the default operator new (thus with an additional parameter, those may be called with the placement new syntax),
providing operator new class members, those will be called only for that class and their descendant.
In the latter two cases, it is possible to call one of the more well know operators new with the syntax:
ptr = ::operator new(sz);
ptr = ::operator new[](sz);
ptr = ::operator new(sz, std::nothrow);
ptr = ::operator new[](sz, std::nothrow);
but if you have replaced them, your replacement will be called. You can't call the default operators new you have replaced (well perhaps you can by playing implementation specific linker tricks, but that's outside the scope of the language).
About the replacement of operator new:
you should replace the two operators new and the corresponding two operator delete together (or one of the delete operator could be easily called with unexpected pointer)
you should replace the two operators new[] and the corresponding two operator delete[] together (same reason)
pay attention to what is possible with the new handlers, some library plays with that.
You can easily perform the check in your overloaded new operator. Be sure to implement all flavours of the new operator (as AProgrammer already pointed out).
Calling the original/default new is not possible, but it's not difficult to implement it yourself. After all, new only allocates memory, that's it. So instead of calling the original/default new, you can also call malloc, HeapAlloc, or any memory-allocation routine found on your system. Be sure to call the corresponding memory-deallocation method (free, HeapFree, ...) in your implementation of delete.
You didn't tell what kind of condition you are going to check in your implementation of new? If it's a 'static' condition (I mean: always giving the same result during the execution of your application), the same condition should also be added to your implementation of delete.
If the condition depends on the situation and changes while running your application, you should foresee a method where you can know which delete implementation to use in your delete function. One trick do to this is the following:
In your implementation of new:
allocate 8 bytes more than requested (this must be 8 bytes to keep the alignment correct)
fill in the first 8 bytes with an identification so that you can know which underlying memory-allocation function you used
add 8 bytes to the allocated pointer and return this one
In your implementation of delete:
subtract 8 bytes of the pointer given to you
check the identification found at that place (see new) to see which kind of underlying delete-implementation you should call

Which operator delete?

Is there a difference between:
operator delete(some_pointer);
and
delete some_pointer;
and if so what is the difference and where one should use one and where the other version of this operator?
Thanks.
Ironically, the delete operator and operator delete() are not the same thing.
delete some_pointer; calls the destructor of the object pointed to by some_pointer, and then calls operator delete() to free the memory.
You do not normally call operator delete() directly, because if you do, the object's destructor will not be called, and you are likely to end up with memory leaks.
The only time you have to care about operator delete() is when you want to do your own memory management by overriding operator new() and operator delete().
To top it off, you should also be aware that delete and delete [] are two different things.
operator delete() simply frees the memory. delete some_pointer calls some_pointer's destructor, and then calls operator delete().
delete some_pointer; is the "correct" one to use.
operator delete(some_Pointer); exist mainly as an artifact of the syntax for defining you own delete operator. That is, because you define an plus operator as;
myclass::operator+(myclass b) {....}
you really could write:
myclass c = a.operator+(b);
but no one ever does that. They use:
myclass c = a + b;
Similarly, you could write operator delete(some_Pointer);, but no one ever does.
At least in my experience, it's more common to implement operator new and operator delete than to actually use (i.e., call) them, at least directly.
Usually, you use operator new and operator delete indirectly -- you write a new expression, like A *a = new A;. To implement this, the compiler generates code that invokes operator new to allocate raw memory, then invokes a A::A to convert that raw memory into an A object, much as if you'd written:
void *temp = operator new(sizeof A); // allocate raw memory with operator new
A *a = new(temp) A; // convert raw memory to object with placement new
When you're done with the object, you use delete A;. To implement that, the compiler invokes the dtor for the object, and then frees the memory, roughly like you'd done:
a->~A();
operator delete(a);
There are also operator [] new and operator [] delete, which are used when/if you allocate/delete arrays -- but there isn't necessarily any real difference between the normal version and the array version -- they both just allocate a specified amount of raw memory (though you might guess that the array versions will allocate relatively large amounts of memory, and do some optimization on that basis).
In any case, if you want to optimize how memory is allocated for objects of a particular class you overload these to do it. There are a fair number of existing implementations that you can drop-in and use, especially for situations where you expect to allocate a large number of tiny objects so you need to minimize the overhead associated with each allocation (e.g., HeapLayers, Loki's small block allocator).
One interesting little tidbit: operator new, operator [] new, operator delete and operator [] deleteare alwaysstaticclass members, even if you don't explicitly includestatic` in their declaration/definition.
There are also global versions of all four (::operator new, ::operator [] new, ::operator delete and ::operator [] delete). These mark the "border" between the "internal" C++ memory management, and the outside world. Typically they allocate relatively large chunks of memory from the operating system, and then return smaller pieces to the rest of the program upon request. If you want to (try to) optimize memory management for your entire program, you typically do it by overloading (or, really, replacing) these. Again, the typical reason would be if you expect to allocate a lot of small objects (but not in just a few classes). One example of this is the Boost Pool library.
Direct use of any of the above is generally restricted to situations where you need a block of raw memory, not objects. One example would be implementing your own container classes. For example, std::vector normally uses ::operator new (via an Allocator object) to allocate memory in which to store objects. Since it needs to be able to allocate storage, but only later (or perhaps never) create objects in that storage, it can't just use something like data = new T[size]; -- it has to allocate raw memory, then use placement new to create objects in the memory as you add them to the collection (e.g., when you push_back an object). The same is true with std::deque. If you wanted (for example) to implement your own circular buffer "from the ground up", handling all the memory management directly instead of using something like vector for storage, you'd probably need/want to do the same.

Why is there a special new and delete for arrays?

What is wrong with using delete instead of delete[]?
Is there something special happening under the covers for allocating and freeing arrays?
Why would it be different from malloc and free?
Objects created with new[] must use delete[]. Using delete is undefined on arrays.
With malloc and free you have a more simple situation. There is only 1 function that frees the data you allocate, there is no concept of a destructor being called either. The confusion just comes in because delete[] and delete look similar. Actually they are 2 completely different functions.
Using delete won't call the correct function to delete the memory. It should call delete[](void*) but instead it calls delete(void*). For this reason you can't rely on using delete for memory allocated with new[]
See this C++ FAQ
[16.13] Can I drop the [] when
deleteing array of some built-in type
(char, int, etc)?
No!
Sometimes programmers think that the
[] in the delete[] p only exists so
the compiler will call the appropriate
destructors for all elements in the
array. Because of this reasoning, they
assume that an array of some built-in
type such as char or int can be
deleted without the []. E.g., they
assume the following is valid code:
void userCode(int n) {
char* p = new char[n];
...
delete p; // ← ERROR! Should be delete[] p !
}
But the above code is wrong, and it
can cause a disaster at runtime. In
particular, the code that's called for
delete p is operator delete(void*),
but the code that's called for
delete[] p is operator
delete[](void*). The default behavior
for the latter is to call the former,
but users are allowed to replace the
latter with a different behavior (in
which case they would normally also
replace the corresponding new code in
operator new[](size_t)). If they
replaced the delete[] code so it
wasn't compatible with the delete
code, and you called the wrong one
(i.e., if you said delete p rather
than delete[] p), you could end up
with a disaster at runtime.
Why does delete[] exist in the first place?
Whether you do x or y:
char * x = new char[100];
char * y = new char;
Both are stored in char * typed variables.
I think the reason for the decision of delete, and delete[] goes along with a long list of decisions that are in favor of efficiency in C++. It is so that there is no enforced price to do a lookup of how much needs to be deleted for a normal delete operation.
Having 2 new and new[] seems only logical to have delete and delete[] anyway for symmetry.
The difference is that delete will only delete the entire memory range, but will only call the destructor for 1 object. delete[] will both delete the memory and call the destructor for every single object. If you do not use delete[] for arrays, it's only a matter of time before you introduce a resource leak into your application.
EDIT Update
According to the standard, passing an object allocated with new[] to delete is undefined. The likely behavior is that it will act as I described.
Stroustrup talks about the reasons for separate new/new[] and delete/delete[]` operators in "The Design and Evolution of C++" in sections 10.3 through 10.5.1:
10.3 Array Allocation - discusses that they wanted a way to allow arrays of objects to be allocated using a separate scheme from allocation single objects (ie., allocating arrays from a separate store). Adding the array versions of new and delete was a solution for this;
10.5.1 Deallocating Arrays - discusses how a problem with deallocating arrays using just a single delete operator is that there needs to be more information than just the pointer in order to determine if the pointer points to the first element of an array or if it just points to a single object. Instead of "complicating the common case of allocating and deallocating individual objects", the delete[] operator is used to handle arrays. This fits in with the general C++ design philiosophy of "don't pay for what you don't use".
Whether this decision was a mistake or not is debatable - either way has good arguments, but we have what we have.
The reason for this requirement is historical and because new type and new type [size] return different things that need to be cleaned up differently.
Consider this code
Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
These both return a Foo* pointer, the difference is the second call will result in the Foo constructor being called 10x, and there being roughly 10x as much memory.
So now you want to free your objects.
For a single object you would call delete - e.g. delete oneEntry. This calls the objects destructor and and deallocates the memory.
But here's the problem - oneEntry and tenEntries are both just Foo pointers. The compiler has no idea whether they point to one, ten, or a thousand elements.
When you use the special syntax of delete []. This tells the compiler "this is an array of objects, figure out the count and then destruct them all".
What really happens is that for new type [size] the compiler secretly stores 'size' somewhere else. When you call delete[] it knows that this secret value exists so it can find out how many objects are in that block of memory and destruct them.
The question you could then ask is "why doesn't the compiler always store the size?"
That's a great question and it dates back to the early days of C++. There was a desire that for built-in types (char, int, float, etc) the following would be valid for C++;
int* ptr = new int;
free(ptr);
int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
The reasoning behind this was an expectation that people would provide libraries that returned dynamically allocated memory, and users of these libraries would have no way of knowing whether to use free/delete.
This desire for compatibility meant that the size of an array could not be stored as part of the array itself and had to be kept elsewhere. Because of this overhead (and remember, this was back in the early 80's) it was decided to do this book keeping only for arrays and not single-elements. Thus arrays need a special delete syntax that looks up this value.
The reason malloc/free do not have this problem is that they simply deal with blocks of memory and do not have to worry about calling constructors/destructors.
As to the "why" in the title: one of the design goals of C++ was that there wouldn't be any hidden costs. C++ was also developed at a time when every byte of memory still mattered a whole lot more than it does today. Language designers also like orthogonality: if you allocate the memory with new[] (instead of new), you should free it with delete[].
I don't think there's any technical reason that new[] couldn't stick an "I'm an array" flag in the header of the memory block for delete (no more delete[]) to look at later.
new and delete are different from malloc and free in that malloc and free only allocate and free memory; they don't call ctors or dtors.
When you use new[] to allocate an array, you are actually telling C++ the size of the array. When you use malloc, you are instead telling it how much memory is allocated. In the former case, freeing based on the size of the array would not make sense. In this case, it does. But since there is no difference between a pointer for an array vs. for a single object, a separate function is needed.