This will have to be accessed by other, non-inhereting classes and my accessor was throwing compiler errors. |
Having that public destroys encapsulation in the worst possible way. It is the single most critical member of your class and should absolutely be private because it is so sensitive.
If you allow other code to tinker with it, it will be very easy to break the class with external code... which makes bugs much harder to find and fix. IE: if anything can access the data, then the bug could be anywhere... but if only this class can access the data, the the bug must be someone in the class code.
If other code needs direct access via a pointer and not through an ArrayList object, then a 'getter' to get a pointer to the data is very easy to write:
|
T* getData() { return data; }
|
I'll consider [passing by const ref], but the methods make use of the non-const getSpecificData method
|
So make getSpecificData const. It doesn't modify the object, does it? It shouldn't.
I'm worried that making it const will cause problems in the rest of my code. |
It shouldn't. I don't see how it possibly could.
This does actually have a class which inherits from it. |
That's weird, but ok.
Explain to me why, unless the overloaded = takes arrays, including both of these isn't redundant. |
The overloaded = would take an ArrayList<T>.
Your problem is this: every time you call any of your >=, ==, etc operator overloads, you are creating a copy of the ArrayList object.
By default... if you do not specify a copy constructor... C++ will do a shallow copy of all members. This means you will have multiple objects pointing to the same memory -- and each object will try to delete[] the memory when the dtor runs -- resulting in the same memory being deleted multiple times (crash).
Since your ArrayList class has strict ownership of the array, and deletes it in its dtor... it MUST do a deep copy to ensure that each ArrayList object has its own memory, therefore when their dtor runs and deletes it, they are not deleting each others data.
Your problem now:
1 2 3 4 5 6 7 8 9 10 11
|
{
ArrayList<int> a(10); // <- allocates a block of memory, let's call that memory 'foo'
{
ArrayList<int> b(a); // <- copy. Shallow copy means no new memory is allocated.
// instead, now both 'a' and 'b' both point to 'foo' memory
} // <- b's dtor runs, delete[]'s foo
// <- here, foo has been deleted, but 'a' is unaware of that fact. If 'a' tries to access
// it, VERY BAD THINGS can happen.
} // <- 'a's dtor will run and try to delete[] foo again... but it has already been deleted
// so it will almost certainly crash.
|
The assignment operator is the same thing... only more severe because it also leaks memory:
1 2 3 4 5 6 7 8 9 10 11
|
{
ArrayList<int> a(10); // <- allocates 'foo'
{
ArrayList<int> b(10); // <- allocates 'bar'
b = a; // <- 'bar' memory is no longer being pointed to and therefore can never
// be deleted. IE: you have a memory leak. Instead, 'b' now points to 'foo'
} // <- b's dtor runs, delete[]'s foo
// <- same deal, 'foo' has been deleted, so 'a' can't access it
} // <- 'a's dtor delete[]s it again. Crash.
|
1. That method isn't really used in my implementation. |
Then why have it?
2. I usually flush my arrays so that the data defaults to '\0'. |
So? What if someone wants to store a value of 0 in the array? If you are using 0 as a special marker, that will screw things up.