C++ 尝试在向量类中创建复制函数

C++ 尝试在向量类中创建复制函数,c++,vector,pass-by-reference,dynamic-allocation,C++,Vector,Pass By Reference,Dynamic Allocation,我正在实现一个vector类,但不知道如何编写函数将一个向量复制到另一个向量 template <class T> class Vec { public: //TYPEDEFS typedef T* iterator; typedef const T* const_iterator; typedef unsigned int size_type; //CONSTRUCTOS, ASSIGNMENT OPERATOR, & DESTRUCTOR

我正在实现一个vector类,但不知道如何编写函数将一个向量复制到另一个向量

template <class T> class Vec {

public:
//TYPEDEFS
    typedef T* iterator;
    typedef const T* const_iterator;
    typedef unsigned int size_type;

//CONSTRUCTOS, ASSIGNMENT OPERATOR, & DESTRUCTOR
    Vec() {this->create(); }
    Vec(size_type n, const T& t = T()) { this->create(n, t); }
    Vec(const Vec& v) { copy(v); }
    Vec& operator=(const Vec& v);
    ~Vec() { delete [] m_data; }

//MEMBER FUNCTIONS AND OTHER OPERATORS
    T& operator[] (size_type i) { return m_data[i]; }
    const T& operator[] (size_type i) const { return m_data[i]; }
    void push_back (const T& t);
    iterator erase(iterator p);
    void resize(size_type n, const T& fill_in_value = T());
    void clear() { delete [] m_data; create(); }
    bool empty() const { return m_size == 0; }
    size_type size() const { return m_size; }

//ITERATOR OPERATIONS
    iterator begin() { return m_data; }
    const_iterator begin() const { return m_data; }
    iterator end() { return m_data + m_size; }
    const_iterator end() const { return m_data + m_size; }

private:
//PRIVATE MEMBER FUNCTIONS
    void create();
    void create(size_type n, const T& val);
    void copy(const Vec<T>& v);

//REPRESENTATION
    T *m_data;      //point to first location inthe allocated array
    size_type m_size;   //number of elements stored in the vector
    size_type m_alloc;  //number of array locations allocated, m_size <= m_alloc
};

//create an empty vector (null pointers everywhere)
template <class T> void Vec<T>::create() {
    m_data = NULL;
    m_size = m_alloc = 0;   //no memory allocated yet
}

//create a vector with size n, each location having the given value
template <class T> void Vec<T>::create(size_type n, const T& val) {
    m_data = new T[n];
    m_size = m_alloc = n;
    for (T* p = m_data; p != m_data + m_size; ++p)
        *p = val;
}   

//assign one vector to another, avoiding duplicate copying
template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v) {
    if (this != &v) {
        delete [] m_data;
        this -> copy(v);
    }
    return *this;
}
模板类Vec{
公众:
//TYPEDEFS
typedef T*迭代器;
typedef常量T*常量迭代器;
typedef unsigned int size_type;
//构造函数、赋值运算符和析构函数
Vec(){this->create();}
Vec(size_type n,const T&T=T(){this->create(n,T);}
向量(const-Vec&v){copy(v);}
向量和运算符=(常量向量和向量);
~Vec(){delete[]m_data;}
//成员函数和其他运算符
T&运算符[](size_type i){返回m_数据[i];}
常量T&运算符[](size_type i)常量{返回m_数据[i];}
无效推回(施工T&T);
迭代器擦除(迭代器p);
调整大小(大小\类型n,常数T和填充\值=T());
void clear(){delete[]m_data;create();}
bool empty()常量{return m_size==0;}
size_type size()常量{返回m_size;}
//迭代器运算
迭代器begin(){return m_data;}
常量迭代器begin()常量{return m_data;}
迭代器end(){return m_data+m_size;}
常量迭代器end()常量{return m_data+m_size;}
私人:
//私人成员职能
void create();
创建空洞(尺寸类型n,常数T&val);
无效副本(const-Vec&v);
//代表
T*m_data;//指向分配数组中的第一个位置
size\u type m\u size;//向量中存储的元素数
size_type m_alloc;//分配的数组位置数,m_size copy(v);
}
归还*这个;
}
这是我想到的第一件事:

template <class T> void Vec<T>::copy(const Vec<T>& v) {

     m_size = m_alloc = v.size();
     m_data = &v;

}
template void Vec::copy(const Vec&v){
m_size=m_alloc=v.size();
m_数据=&v;
}
关于不兼容类型,我有一个错误…好的,它们是不兼容的。所以我去掉了“const”,现在它工作了

template <class T> void Vec<T>::copy(Vec<T>& v) {

     m_size = m_alloc = v.size();
     m_data = &v[0];

}
template void Vec::copy(Vec&v){
m_size=m_alloc=v.size();
m_数据=&v[0];
}

我猜这不是完全正确或好的形式。我不确定。现在我得到一个错误,指针被释放,但没有被分配(但它至少现在成功地编译、运行和复制了向量)。所以我想说我并不真正理解通过引用传递变量/数组/向量/事物,也不理解内存的动态分配。我的问题是:如何改进我编写的复制函数,使其不比较两个不兼容的变量,或者成功地将指针动态分配到新向量,以便不出现malloc错误?

您需要对元素进行深度复制,而不是简单地分配指针
m_data

// precondition: `m_data` is not allocated
template <class T> void Vec<T>::copy(const Vec<T>& v) {
    m_data = new T[v.size()];
    m_size = m_alloc = v.size();
    for (size_t ii = 0; ii < m_size; ++ii)
        m_data[ii] = v[ii];
}
//前提条件:`m_data`未分配
模板void Vec::复制(const Vec&v){
m_数据=新T[v.尺寸()];
m_size=m_alloc=v.size();
对于(尺寸ii=0;ii
注意,前面给出的答案中存在异常安全问题。简单的解决方法是先分配

// precondition: `m_data` is not allocated
template <class T> void Vec<T>::copy(const Vec<T>& v) {
    m_data = new T[v.size()];
    m_size = m_alloc = v.size();
    for (size_t ii = 0; ii < m_size; ++ii)
        m_data[ii] = v[ii];
}
基本上,我们从
v
构造一个临时变量,删除
this->m_数据,然后将
temp
的元素分配给
this
。然后我们通过将
temp.m_data
data设置为NULL来去除
temp
的内脏。这需要这样做,以便当
temp
死亡时,我们不想
删除
分配给
的数据

注意,如果第一行
Vec temp=v引发异常,不会对
造成任何伤害
这样就提供了异常安全性

下面是“复制/交换”的习惯用法,正如
长颈鹿船长所建议的那样:

template <class T> class Vec {
//...
  void swap(Vec<T>& left, Vec<T>& right);
//..
};

template <class T> void Vec<T>::swap(Vec<T>& left, Vec<T>& right)
{
    std::swap(left.m_size, right.m_size);
    std::swap(left.m_alloc, right.m_alloc);
    std::swap(left.m_data, right.m_data);
}

template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v)
{
    // construct a temporary
    Vec<T> temp = v;
    swap(*this, temp);
    return *this;
}
模板类Vec{
//...
无效掉期(Vec和左、Vec和右);
//..
};
模板void Vec::swap(Vec&左、Vec&右)
{
标准::交换(左.m_大小,右.m_大小);
标准::交换(left.m_alloc,right.m_alloc);
std::swap(左.m_数据,右.m_数据);
}
模板向量和向量::运算符=(常量向量和向量)
{
//建造临时建筑物
向量温度=v;
交换(*本,临时);
归还*这个;
}

这里的区别在于,我们将
temp
的成员替换为
this
。由于
temp
现在将包含
this
过去拥有的指针,因此当
temp
死亡时,它将调用
delete
来删除此“旧”数据。

为了使复制构造函数安全,需要在无法复制时失败

Vec<T>::Vec(const Vec<T>& o):m_size(o.m_size), m_alloc(o.m_size), m_data(new T()){
    std::copy( o.m_data, o.m_data+o.m_size, m_data);
}
Vec::Vec(const-Vec&o):m_大小(o.m_大小)、m_分配(o.m_大小)、m_数据(新T()){
std::复制(o.m_数据,o.m_数据+o.m_大小,m_数据);
}
复制构造函数应该能够替换任何Vec::copy成员

通过引入交换函数,可以轻松处理赋值。这是异常安全的

void Vec<T>::swap(Vec<T>& rhs){
   std::swap(m_data, rhs.m_data);
   std::swap(m_size, rhs.m_size);
   std::swap(m_capacity, rhs.m_capacity);
}
void Vec::swap(Vec&rhs){
标准::交换(m_数据,rhs.m_数据);
标准:交换(m_尺寸,rhs.m_尺寸);
标准:交换(m_容量,rhs.m_容量);
}
除了安全复制、交换和惯用语之外,它变成:

Vec<T>& Vec<T>::operator = (const Vec<T>& rhs){
   Vec<T> cpy=rhs;
   swap( this, cpy);
   return *this;
}
Vec&Vec::operator=(const-Vec&rhs){
Vec-cpy=rhs;
掉期(本,cpy);
归还*这个;
}

您不需要调用
size()
。在复制构造函数中,您可以访问参数的私有变量,因此
m_size=m_alloc=v.m_size
就可以了。其次,不要做
m_data=&v。你应该复制缓冲区,而不是引用。你所做的不是复制一个向量,而是共享一个向量(这可能会在以后导致双重释放和分段错误)。如果你真的想复制一个向量,你需要分配内存并复制所有元素(比如说,
std::copy
)。如果你真的想复制一个向量,你只需清除
这个
,然后在一个循环中,为向量
v
中的每个元素调用push_back()。你的
操作符=
有故障。您删除了
m_数据
,因此如果在尝试分配内存时引发异常
Vec<T>& Vec<T>::operator = (const Vec<T>& rhs){
   Vec<T> cpy=rhs;
   swap( this, cpy);
   return *this;
}