First of all, there is a major problem with your class: it does not respect the rule of three/five/zero:
it has a non trivial destructor that destroys memory allocated in constructor
it neither defines nor deletes the copy constructor and assignment operator Let us look at the following code:
DynamicArray dynarr[16]; // initialize values in dynarr if (...) { // opens a nested block DynamicArray dynarr2 = dynarr; // copy construct the new DynamicArray (1) // use it } // dynarr2 goes out of scope (2)
At (1), the compiler generated copy constructor will blindly copy the member, having dynarr and dynarr2 share their inner int array.
At (2), the dtor for dynarr2 will delete the shared inner array: ZAP!... dynarr now has a dangling pointer, Undefined Behaviour is ensured from there....
There is another possible error in size management. You consistently divide it by 2 when removing elements and multiply it by 2 when adding. Fine. Except that if you let the size reach 0 by removing the last element of a DynamicArray 0*2 is still 0 so the size will be definitively stuck at 0! You must handle that corner case by preventing the size to reach 0 in shrink.
What follow are only minor possible improvements.
Your code uses
using namespace std;This is not an error because it is allowed by the language, and is even common in many tutorials. It is a nice trick that allows to use all the goodies from the standard library without the
std::prefix. But, it does import a number of useless symbols into the current namespace, somhowsomehow defeating the whole namespace concepts. In production code, best practices recommend to never useusing namespace stdbut only import the relevant symbols. Only a cosmetic improvement.in
checkIndex, you usethrow "Index is out of the array range!";This actually throws a pointer to a string litteral. Here again it is not an error since it is allowed by the language. But best practices recomment to only throw objects of (subclasses of) the
std::exceptionclass. Users of your class will probably not expect to have to catch a char pointer. You'd better use anout_of_rangeor aruntime_errorexception if you think it is not worth declaring a custom exceptionYou compare
sizeandnewsizeincopyToNewSizeto know how many elements should be copied. But in fact you have only to copylengthelements... This one is only a tiny optimization.
For your initial question, there is nothing bad in only shrinking after a number of removals, because a shrink involve reallocation and a copy of the elements, so it is an expensive operation. For that reason, you should even considere stop shrinking below a threshold (for example 8 elements). As a bonus, it will directly prevent size to reach 0, and you could even make that minimal size an optional parameter of your constructor.