What is the Time Complexity of the delete[]
operator?
I mean how is it implemented - does it iterate over all the elements in the array and calls destructor for every element?
Does this operator do the same for primitive types (int
, etc.) and user defined types?
delete is used for one single pointer and delete[] is used for deleting an array through a pointer.
What is the difference between delete and delete[] in C++? a) delete is used to delete normal objects whereas delete[] is used to pointer objects. b) delete is a keyword whereas delete[] is an identifier. c) delete is used to delete single object whereas delete[] is used to multiple(array/pointer of) objects.
Delete is an operator that is used to destroy array and non-array(pointer) objects which are created by new expression. Delete can be used by either using Delete operator or Delete [ ] operator. New operator is used for dynamic memory allocation which puts variables on heap memory.
Delete - O(1)
::operator delete[]
is documented on cplusplus.com (which is sometimes frowned upon) as:
operator delete[]
can be called explicitly as a regular function, but in C++,delete[]
is an operator with a very specific behavior: An expression with thedelete[]
operator, first calls the appropriate destructors for each element in the array (if these are of a class type), and then calls functionoperator delete[]
(i.e., this function) to release the storage.
so the destructor is called n times (once for each element), and then the memory freeing "function" is called once.
Notice that each destruction might take a different time (or even complexity) than the others. Generally most destructions are quick, and have the same complexity.... But that won't be the case if each destroyed element is a complex tree or node or graph...
For primitive types like int
the fictitious destructor of int
is a no-op. The compiler probably would optimize that (if asked).
You should check the real C++11 standard, or at least its late n3337 working draft, which says (thanks to Matteo Italia for pointing that in a comment) in §5.3.5.6 page 110 of n3337:
If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted. In the case of an array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see 12.6.2)
If you use -and trust enough- GCC 4.8 or better, you could have used the g++
compiler with the -fdump-tree-phiopt
or -fdump-tree-all
option (beware, they are dumping a lot of files!), or the MELT plugin, to query the intermediate Gimple representation of some example. Or use -S -fverbose-asm
to get the assembler code. And you also want to add optimization flags like -O1
or -O2
...
NB: IMHO, cppreference.com is also an interesting site about C++, see there about delete
(as commented by Cubbi)
The implementation of delete
and delete[]
is composed of two phases:
Let alone the chain of calls to destructors, whose complexity is essentially governed by you, we are left with how the memory is freed to consider.
The second point is not covered by the C++ specification. So, any compiler suite/OS is free to adopt its own strategy.
A common memory allocation/deallocation strategy is allocating a whole memory page when needed from the OS, then at each new
/new[]
, returning a chunk of the appropriate size, whose length and attributes are then stored inside the page as a header/footer. A corresponding delete
/delete[]
can be as simple as marking that same chunk as "free", which is clearly O(1).
If the complexity of memory deallocation is O(1), then the complexity of a delete
is essentially governed by calls to destructors. The default implementation does (almost) nothing, and it's a O(1) for a single call, thus an overall O(n), where n is the toal number of calls (e.g. if the object being destructed has two fields whose destructor is called, then n = 1 (object) + 2 (o. fields) = 3
).
Putting all pieces together: you can arbitrarily increment complexity by performing operations in the destructor (which can be written by you), but you cannot "perform better"¹ than O(n) (n defined in the previous paragraph). The formally correct way to state this is: "the complexity of delete
is an Omega(n)".
¹ allow me to be a bit informal on this point
For class types, the theoretical complexity is O(n)
. The destructor is called for each element. Of course, it's up to the implementation to adhere to the observable behavior, so if the destructor is a no-op or the behavior is the same as with just marking the whole chunk as freed, the complexity could be just O(1)
.
For primitive types, the compiler will likely just release the whole chunk of memory at once, thus the complexity O(1)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With