#include <algorithm>
#include <utility>
#include <new>
#include <iostream>
template <typename T>
class Vector {
public:
Vector();
~Vector();
void push_back(const T& value);
void push_back(T&& value);
void clear();
std::size_t size() const { return sz; }
std::size_t capacity() const { return cap; }
T& operator[](std::size_t i) { return data[i]; }
const T& operator[](std::size_t i) const { return data[i]; }
private:
T* data;
std::size_t sz;
std::size_t cap;
void p_realloc(std::size_t n);
};
template <typename T>
Vector<T>::Vector()
: sz{}, cap{ 10 }
{
data = (T*)::operator new(cap * sizeof(T));
}
template <typename T>
Vector<T>::~Vector() {
clear();
::operator delete(data, sizeof(T) * cap);
}
template <typename T>
void Vector<T>::p_realloc(std::size_t n) {
T* new_data = (T*)::operator new(n * sizeof(T));
if (n < sz)
sz = n;
for (std::size_t i = 0; i < sz; ++i) {
new_data[i] = std::move(data[i]);
data[i].~T();
}
::operator delete(data, cap * sizeof(T));
data = new_data;
cap = n;
}
template <typename T>
void Vector<T>::clear() {
for (std::size_t i = 0; i < sz; ++i)
data[i].~T();
sz = 0;
}
template <typename T>
void Vector<T>::push_back(const T& value) {
if (sz >= cap)
p_realloc(cap * 1.5);
data[sz++] = value;
}
template <typename T>
void Vector<T>::push_back(T&& value) {
if (sz >= cap)
p_realloc(cap * 1.5);
std::cout << "All good\n"; std::cin.get();
data[sz++] = std::move(value);
}
I am trying to create a custom implementation of Vector class. I have already made one but it does not use ::operator new and delete in order to not call the constructor/destructor. When T=std::string and i try to call push_back("test_string") i get an error and i cannot figure about why. Should it not be implicitly converted to std::string and therefore data[sz++] = std::move(value) work ?
The error is not in the using push_back(T&&). The reason is in the data
that points to an uninitialized memory.
data[sz++] = value;
calls T::operator=(const T&)
on an uninitialized object T.
data[sz++] = std::move(value);
calls T::operator=(T&&)
on an uninitialized object T.
You should fix assignments data[sz++] =
in the both push_back
with using the placement new:
/* data[sz++] = value; */ new (&data[sz++]) T(value);
/* data[sz++] = std::move(value); */ new (&data[sz++]) T(std::move(value));