Is there any difference between fncs: operator new and operator new[] (NOT new and new[] operators)? Except of course call syntax? I\'m asking because I can allocate X numbe
In your example code, you're using placement new
to perform the construction that operator new[]
performs automatically - with the difference that new[]
will only perform default construction and you're performing a non-default placement construction.
The following is more or less equivalent to your example:
#include <iostream>
using namespace std;
struct X
{
int data_;
X(int v=0):data_(v){}
};
int main(int argc, char* argv[])
{
unsigned no = 10;
X* xp = new X[no];
for (unsigned i = 0; i < no; ++i) {
X tmp(i);
xp[i] = tmp;
}
for (unsigned i = 0; i < no; ++i)
{
cout << (xp[i]).data_ << '\n';
}
delete[] xp;
return 0;
}
The differences in this example are:
new
is a pretty advanced technique that isn't often used, so isn't often understood)I think that in general, using new[]
/delete[]
is a much better than allocating raw memory and using placement new
to construct the objects. It pushes the complexity of the bookkeeping into those operators instead of having it in your code. However, if the cost of the "default construct/set desired value" pair of operations is found to be too costly, then the complexity of doing it manually might be worthwhile. That should be a pretty rare situation.
Of course, any discussion of new[]
/delete[]
needs to mention that using new[]
/'delete[]should probably be avoided in favor of using
std::vector`.
As user sankoz explains in his answer to in fact the same question, having separate operator new[]
is intended for overloading single object allocations and array allocations separately in classes.
For example, if you have some specific class and you know that its instances are never larger than say 50 bytes you might want to overload operator new
for that class so that its instances are allocated on a superfast allocator for blocks of size 50.
But what if the user calls new[]
? The array can have whatever number of elemenents, so you can't universally allocate them on your custom allocator. The solution is you don't have to care of array allocations unless you want to.
Allocation is one thing, object construction/destruction is another.
A new
performs one allocation and one construction. However, a new[]
still allocates one continuous memory block, but calls many constructors.
The situation is the same with delete
and delete[]
.
BTW- I'm not 100% sure with what I'm about to say, but I believe that you won't get an imemdiate memory leak if you call delete
on an address received from new[]
. The whole memory block would probably be freed. However, this is invalid because you'd call the destructor on the first object only, instead of on every object in the array. And this may result in secondary memory leaks... and lots of logic errors due to broken 1-1 relation of constructors and destructors, of course.
(Also, remember to consider using boost::array
or std::vector
instead of new[]
! :))
There's not a whole lot of difference between the required behavior of the functions void* operator new(size_t)
and void* operator new[](size_t)
, except that they're paired with different deallocation functions.
The operators themselves are very different. One of the differences between the operators is which allocation function is used, but there are ultimately many other differences including how many constructors get called, etc. But your example code isn't using the operators (well, it is using placement new). You might want to change your question title to be clear about that.
From section [basic.stc.dynamic.deallocation]
:
If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied to
operator delete(void*)
in the standard library shall be one of the values returned by a previous invocation of either operatornew(std::size_t)
or operatornew(std::size_t, const std::nothrow_- t&)
in the standard library, and the value supplied tooperator delete[](void*)
in the standard library shall be one of the values returned by a previous invocation of eitheroperator new[](std::size_t)
oroperator new[](std::size_t, const std::nothrow_t&)
in the standard library.
These functions (operator new
etc.) are not generally intended to be called explicitly, but rather used implicitly by new
/new[]
expressions (symmetrically, operator delete
/operator delete[]
functions are invoked implicitly by delete
/delete[]
expressions). An expression that uses new
syntax for non-array type will implicitly call operator new
function, while an expression with new[]
will implicitly call operator new[]
.
The important detail here is that an array created by new[]
expression will normally be destroyed later by delete[]
expression. The latter will need to know the number of objects to destruct (if the objects have non-trivial destructors), i.e. this information has to be passed somehow from new[]
expression (when it was known) to the corresponding delete[]
expression (when it is needed). In a typical implementation this information is stored inside the block allocated by new[]
expression, which is why the memory size requested in the implicit call to operator new[]
is normally greater than the product of the number of elements and the element size. The extra space is used to store the household information (number of elements, namely). Later delete[]
expression will retrieve that household information and use it to invoke the correct number of destructors before actually freeing the memory by calling operator delete[]
.
In your example you are not using any of these mechanisms. In your example you are calling memory allocation functions explicitly, perform construction manually and completely ignore the destruction step (which is OK, since your object has trivial destructor), which means that at least for destruction purposes you don't need to track the exact number of elements in the array. In any case, you keep track of that number manually, in a no
variable.
However, in general case it is not possible. In general case the code will use new[]
expressions and delete[]
expressions and the number of elements will have to get from new[]
to delete[]
somehow, meaning that it has to be stored internally, which is why there's a need for a dedicated memory allocation function for arrays - operator new[]
. It is not equivalent to a mere operator new
with the aforementioned product as size.