不要使用std::memcpy
您只能std::memcpy
在可简单复制的对象上使用。否则它是未定义的行为。
但是,您可以手动复制所有元素。std::copy
是合适的,因为它可能专门用于琐碎的类型:
在实践中,std::copy
避免多次赋值并使用批量复制功能的实现,例如std::memcpy
如果值类型是 TriviallyCopyable
template <typename T>
void Vector<T>::push_back(const T& item) {
if (_size == _capacity) {
size_t new_cap = _capacity > 0 ? 2 * _capacity : 2;
T * newVec = new T[new_cap];
std::copy(_ptr, _ptr + _size, newVec);
std::swap(_capacity, new_cap);
std::swap(_ptr, newVec);
delete[] newVec;
}
_ptr[_size++] = item;
}
请注意,如果向量太小,您的原始实现会划分容量。
更多改进
如果您使用std::allocator
(或兼容的类),事情会变得容易一些。您将用于.allocate
获取内存、.construct(pointer, value)
实际构造对象、.destroy
调用它们的析构函数并.deallocate
删除以前使用.allocate
. 因此,如果您只想使用.push_back()
.
以下代码是一个快速的最小草图。请注意,存在一些问题,例如reserve()
不是异常安全的,因为tmp
如果构造函数抛出,则需要清理分配的内存。
template <typename T, class Allocator = std::allocator<T> >
class Vector{
public:
typedef typename Allocator::pointer pointer;
typedef typename Allocator::size_type size_type;
Vector() : _ptr(0), _capacity(0), _size(0){}
~Vector() {
if(_capacity == 0)
return;
while(_size > 0)
pop_back();
_alloc.deallocate(_ptr, _capacity);
}
void reserve(size_type new_cap){
if(new_cap <= _capacity)
return;
// allocate memory
T * tmp = _alloc.allocate(new_cap);
// construct objects
for(unsigned int i = 0; i < _size; ++i){
_alloc.construct(tmp + i, _ptr[i]); // or std::move(_ptr[i])
}
// finished construction, save to delete old values
for(unsigned int i = 0; i < _size; ++i){
_alloc.destroy(_ptr + i);
}
// deallocate old memory
_alloc.deallocate(_ptr, _capacity);
_ptr = tmp;
_capacity = new_cap;
}
void push_back(const T& val){
if(_size == _capacity)
reserve(_capacity > 0 ? 2 * _capacity : 1);
_alloc.construct(_ptr + _size, val);
_size++; // since T::T(..) might throw
}
void pop_back(){
_alloc.destroy(_ptr + _size - 1);
_size--;
}
T& operator[](size_type index){
return _ptr[index];
}
private:
pointer _ptr;
size_type _capacity;
size_type _size;
Allocator _alloc;
};