C++ 像std::vector这样的向量类的简单实现

C++ 像std::vector这样的向量类的简单实现,c++,vector,stl,C++,Vector,Stl,我正在实现一个简单的向量,比如std::vector,我编写了一些函数,而不用担心它提供了什么样的异常安全保证。我知道一些关于C++的异常,但是我没有经历过异常安全代码的编写。 这是我的密码: template <typename T> class vector { public: vector(int _DEFAULT_VECTOR_SIZE = 10) : size(0), array_(new T[_DEFAULT_VECTOR_SIZE]), capaci

我正在实现一个简单的向量,比如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;
 };
模板
类向量{
公众:
向量(int\u默认值\u向量大小=10):
大小(0),数组(新的T[\u默认值\u向量\u大小]),容量(\u默认值\u向量\u大小){}
无效推回(T&elem)
{
如果(大小=容量)
调整大小(2*大小);
数组\[size]=elem;
大小++;
}
void pop_back()
{
--大小;
}
无效调整大小(整型大小)
{
如果(大小>容量)
{
T*temp=新的T[尺寸];
memcpy(温度、数组、大小*sizeof(T));
交换(临时、阵列);
删除[]数组;
容量=大小;
}
}
私人:
T*数组u;
整数大小;
国际能力;
};
所以我的问题是:我如何修改我的代码(函数),这将至少提供基本的保证,或者一些为基本或强保证编写异常安全代码的技术?
谢谢

例外安全主要有两种口味:

  • 如果发生异常,程序将以正常状态结束。哪一个是未指明的
  • 如果发生异常,程序将以原始状态结束
  • 您面临的主要挑战是如何处理赋值和复制构造函数。正如注释已经指出的,您不应该使用
    memcpy
    ,因为这无法调用复制构造函数。例如,复制
    std::string
    还应该复制字符缓冲区,字符串向量是一种您应该支持的完全正常的类型

    让我们看看向量的复制构造函数。它需要复制源向量的每个元素。每个副本都可以抛出。如果其中一个字符串太长以至于副本抛出
    std::bad_alloc
    ,该怎么办

    现在,异常安全意味着您使程序处于正常状态,因此不会出现内存泄漏。向量的复制ctor失败,因此dtor无法运行。那么谁来清理T*数组呢?这必须在您的副本中完成

    当复制失败时,将不会有新的向量,因此您可以免费获得第二种类型的异常安全。(“强异常安全”)。但接下来让我们看看赋值运算符,
    v2=v1
    。您将覆盖一个旧向量。如果先执行
    .resize(0)
    ,然后复制所有元素,则在复制过程中可能会遇到异常。原始矢量内容已消失,新内容不完整。不过,您还没有泄漏任何内存,也没有复制半个元素

    为了使赋值安全,有一个简单的技巧:首先将源向量复制到临时向量。如果失败,则没有问题(见上文)。我们还没有到达目的地。但是如果赋值成功,我们交换临时向量和目标向量的
    数组*
    指针、
    大小
    容量
    。交换指针和整数是安全的(不能抛出)。最后,我们让临时向量超出范围,从而破坏不再需要的旧向量元素

    因此,通过对临时对象执行所有危险的操作,我们可以确保任何异常都不会触及原始状态


    您需要检查所有方法,看看这些问题是否会发生,但模式通常是相似的。如果元素副本或元素分配抛出,请不要泄漏数组,一定要将该异常传播给调用方。

    尝试{/*抛出异常的代码*/}捕获{/*处理异常*/}
    ,据我记忆所及,我希望您意识到这有多错误:
    memcpy(temp,array,size*sizeof(t))
    为什么memcpy(temp、array、size*sizeof(T))错误?@SenoAlvrtsyan
    memcpy
    只适用于
    int
    等POD类型或非常简单的类。另见@SenoAlvrtsyan:简短回答:是。但您可以将其扩展为一个体面的新问题(请展示您的
    .resize
    实现),并在该问题中解释您特别想知道
    std::copy
    在使用时的异常安全性。