试图在矢量类中创建复制功能

时间:2014-08-24 01:32:42

标签: c++ vector pass-by-reference dynamic-allocation

我正在实现一个矢量类,但无法弄清楚如何编写一个函数来将一个矢量复制到另一个矢量中。

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;
}

这是我提出的第一件事:

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

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

}

我收到了关于不兼容类型的错误...好吧,他们认为它们是不兼容的。所以我把'const&#39;现在它的工作原理。

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

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

}

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

3 个答案:

答案 0 :(得分:6)

您需要对元素进行深层复制,而不是简单地指定指针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];
}

答案 1 :(得分:3)

为了使copy-constructor安全,当无法复制时,它需要失败。

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&lt; T&gt; :: 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);
}

除了安全 Copy&amp;交换&amp;成语它变成了:

Vec<T>& Vec<T>::operator = (const Vec<T>& rhs){
   Vec<T> cpy=rhs;
   swap( this, cpy);
   return *this;
}

答案 2 :(得分:2)

请注意,前一个答案给出了异常安全问题。简单的解决方法是先分配。

// 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];
}

您的代码的另一个问题是operator=,这不是例外安全。您在使用m_data重新分配之前删除了new[]。如果new[]失败,则您的对象已损坏。

如上所述修复copy后,可以根据复制构造函数编写operator =

template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v) 
{
    // construct a temporary
    Vec<T> temp = v;

    // set the members
    m_size = m_alloc = temp.size();
    delete [] m_data;
    m_data = temp.m_data;

    // Now set temp.m_data to 0, so that destruction of temp doesn't delete
    // our memory
    temp.m_data = 0;
    return *this;
}

基本上,我们从v构建一个临时文件,删除this->m_data,然后将temp的元素分配给this。然后,我们通过将temp数据设置为NULL来删除temp.m_data的内容。这需要完成,以便在temp死亡时,我们不希望delete我们分配给this的数据。

请注意,如果第一行Vec<T> temp = v;引发异常,则对this不会造成任何损害 完成后,提供了例外安全。

以下是Captain Giraffe建议的复制/交换习惯用语:

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;
}

这里的不同之处在于我们将temp的成员与this进行交换。由于temp现在将包含this曾经拥有的指针,当temp死亡时,它将在此&#34;旧&#34;上调用delete。数据