I am trying to construct a template of an array class to implement a dynamic array of objects of arbitrary type: Type.
The basic class declaration appears below.
1) My getElem / setElem member functions currently have return/argument types: Type. I was considering using return/arguments of type *Type. This alternative seems to be appropriate if Type is a "large" type for which passing by value might be time consuming.
Does passing by value invoke the copy constructor of the class Type? What about passing by reference?
Are these significant design concerns? Is there a disadvantage to using *Type? Should I consider passing by reference?
2) Besides the default constructor, which does very little, I plan to implement a constructor that, when supplied with a positive integer size, allocates memory for size many objects.
I was planning to use malloc(sizeof(Type)*size) to allocate space for size many objects. Later, when actual objects are stored in the array A, I would simply use an assignment like:
A[index] = newObject;
Presumably, if Type has a copy constructor, this is when it would be invoked.
An alternative implementation for this constructor is to (somehow?) use "new[]" to create size many objects of type: Type. I guess I have to assume that Type has a default constructor for this.
Are these two plans for implementing the constructor both feasible? If so, is one preferable to the other?
I was planning to use malloc(sizeof(Type)*size) to allocate space for size many objects. Later, when actual objects are stored in the array A, I would simply use an assignment like:
A[index] = newObject;
Presumably, if Type has a copy constructor, this is when it would be invoked.
This would not invoke a copy constructor. It would invoke the copy assignment operator, which would be a disaster for any non-trivial type (e.g. if Type = std::string)
I have to assume that Type has a default constructor for this.
Yes, new-ing C-style arrays requires that the elements are default-constructible. You can work around that with uninitialized storage (std::get_temporary_buffer() etc), but the normal C++ approach to a resizeable array is std::vector, which doesn't require its elements to be default constructible (or even copyable, for that matter)
I understand that std::vector is best for this kind of thing. I'm just trying to implement this on my own as an educational exercise.
Why is invoking a copy assignment operator disastrous? Is it that much worse than invoking a default constructor?
Also, I suspect that it's bad style to mix c-style memory functions (like realloc) with c++-style functions (new, delete), but how else can you increase the size of an array without having to create a new larger array and copy the old elements into it?
Why is invoking a copy assignment operator disastrous?
Because there are no objects in your malloc()'d memory block, nothing was constructed, and you're calling a member function (copy assignment operator is a member function), which modifies the object (e.g. for std::string it will try to free the old string's heap-allocated storage).
You could create objects in malloc()'d storage using std::allocator<Type>::construct(), if you really want to write something similar to a vector. It depends on what exactly you're trying to learn.
suspect that it's bad style to mix c-style memory functions (like realloc) with c++-style functions (new, delete), but how else can you increase the size of an array without having to create a new larger array and copy the old elements into it?