我正在实现一个矢量类,但无法弄清楚如何编写一个函数来将一个矢量复制到另一个矢量中。
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错误?
答案 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
。数据