[英]Simple implementation of vector class like std::vector
我正在实现一个简单的向量,例如std :: vector,并且编写了一些函数,而不必担心它会提供哪种异常安全保证。 我对C ++的异常了解得很少,但是我还没有编写异常安全代码的经验。 这是我的代码:
template <typename T>
class vector {
public:
vector(int _DEFAULT_VECTOR_SIZE = 10) :
size(0), array_(new T[_DEFAULT_VECTOR_SIZE]), capacity(_DEFAULT_VECTOR_SIZE) {}
void push_back(T& elem)
{
if (size == capacity)
resize(2 * size);
array_[size] = elem;
size++;
}
void pop_back()
{
--size;
}
void resize(int size_)
{
if (size_ > capacity)
{
T* temp = new T[size_];
memcpy(temp,array_,size*sizeof(T));
swap(temp, array_);
delete[] array_;
capacity = size_;
}
}
private:
T* array_;
int size;
int capacity;
};
所以我的问题是:如何修改我的代码(函数),至少可以提供基本保证,或者为基本保证或强保证提供某种编写异常安全代码的技术? 谢谢
异常安全有两个主要方面:
您面临的主要挑战是处理分配和复制构造函数的抛出。 正如评论已经指出的那样,您不应该使用memcpy
因为那样将无法调用副本构造函数。 例如,复制std::string
还应该复制字符缓冲区,字符串向量是您应该支持的完全正常的类型。
因此,让我们看一下向量的副本构造函数。 它将需要复制源向量的每个元素。 每个副本都可以抛出。 如果其中一个字符串太长而导致副本抛出std::bad_alloc
怎么办?
现在,异常安全性意味着您将程序保持在理智状态,因此不会发生内存泄漏。 向量的复制ctor失败,因此dtor无法运行。 谁清理T* array
呢? 这必须在您的复制控制器中完成。
复制失败时,将不会有新的向量,因此您可以免费获得第二种异常安全性。 (“异常安全性强”)。 但是接下来让我们看一下赋值运算符v2 = v1
。 有一个旧的向量将要覆盖。 如果首先执行.resize(0)
,然后复制所有元素,则复制过程中可能会遇到异常。 您原来的矢量内容已消失,新内容不完整。 不过,您还没有泄漏任何内存,也没有复制一半的元素。
为了使分配安全,有一个简单的技巧:首先将源向量复制到临时向量。 如果失败,则没有问题(请参见上文)。 我们尚未触及目的地。 但是,如果分配成功,我们将交换array*
指针,临时矢量和目标矢量的size
和capacity
。 交换指针和交换int是安全的(不能抛出)。 最后,我们让临时向量超出范围,这会破坏不再需要的旧向量元素。
因此,通过对临时对象执行所有危险操作,我们确保任何异常都不会触及原始状态。
您需要检查所有方法,看看是否会发生这些问题,但是这种模式通常是相似的。 如果元素副本或元素分配抛出异常,请勿泄漏array
,请将该异常传播给调用者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.