I am trying to implement my own versioin of std::vector for practice. This is my first time working with templates so it's possible the solution is trivial but I have not been able to find anything on Google. The vector class I created has a template T which is supposed to be the variable type the vector is storing. In the push_back() function I am using "T value" as the argument. If I understand correctly that should make the function able to use whatever value the vector is initialized to store as the argument.
In main I am calling myvector.push_back(100) and getting the following error:
no instance of function template "myVector<T>::push_back [with T=int]" matches the argument listC/C++(304)
CustomContainer.cpp(112, 13): argument types are: (int)
CustomContainer.cpp(112, 13): object type is: myVector<int>
as well as:
"no matching function for call to 'myVector::push_back(int)'".
Here is my code:
template <typename T>
class myVector
{
private:
int my_size = 0;
int capacity = 1;
T* arr;
public:
myVector()
{
my_size = 0;
capacity = 1;
arr = new T[1];
}
myVector(unsigned int new_cap)
{
capacity = new_cap;
arr = new T[new_cap];
}
myVector(unsigned int new_cap, T content)
{
capacity = new_cap;
arr = new T[new_cap];
std::fill_n(*arr, new_cap, content);
}
~ myVector()
{
delete[] arr;
}
template <typename C>
void push_back(T value)
{
if(my_size < capacity)
{
capacity = ceil((double)capacity * 1.5);
C* temp = new C[capacity];
std::copy(std::begin(arr), std::end(arr), std::begin(temp));
delete arr;
arr = temp;
temp = NULL;
my_size++;
}
arr[my_size++] = value;
}
//more methods here, none of which are named "push_back"
};
int main()
{
myVector<int> poggers;
poggers.push_back(100);
}
I have tried creating the following function:
void push_back(int value)
{
}
and it made the error go away so it looks to me like a templates issue.
Any class design critique is also welcome.
The function is generally broken. You should not be using a distinct template parameter type C
, when the class itself stores type T
. Otherwise you'll get type mismatches when you allocate a new array of C
.
You were also using the wrong delete
in that function, and std::begin
/ std::end
don't work for raw pointers. Just use the pointers themselves, as they are compatible with iterators.
It's also not a great idea to use floating point arithmetic for the expansion. You can use integers instead. Although it's a bit fiddly due to your initial size of 1, you can handle the size-1 edge case by adding 1 and avoiding any branching:
capacity += (capacity + 1) / 2;
Also made the argument a reference instead of copy, and removed a double size increase.
The not-large-enough test was backwards. You need my_size == capacity
. More "accident-proof" to use my_size >= capacity
, I think, but watch out for future logic if you're pushing multiple values at once. You'll need to ensure that you select a large enough size.
void push_back(const T& value)
{
if(my_size >= capacity)
{
capacity += (capacity + 1) / 2;
T* temp = new T[capacity];
std::copy(arr, arr + my_size, temp);
delete[] arr;
arr = temp;
}
arr[my_size++] = value;
}
Note that it's probably not a good idea to use int
for the sizes. Containers use an unsigned type, and usually std::size_t
. You may want to add safety by ensuring you do not overflow your capacity when enlarging the vector.
Because you have a non-trivial class with raw memory management, you'll need copy constructor / copy-assignment. See What is the Rule of Three?
Consider also supporting move-semantics. Not only for push_back
(avoiding the copy of non-trivial types that you may want to store in the vector) but more generally for your move-construction / move-assignment.
Instead of managing raw pointers, it would be cleaner to use std::unique_ptr
.