[英]How is std::erase implemented for vectors?
I have a custom Vec class, duplicating the functionality of std::vector, but I am unable to implement an erase function which takes the same parameters as the standard library implementation (and handles them elegantly). 我有一个自定义的Vec类,它复制了std :: vector的功能,但是我无法实现一个采用与标准库实现相同的参数(并优雅地处理它们)的擦除函数。 Specifically, in C++11, vector::erase has the signature
iterator erase (const_iterator position);
具体来说,在C ++ 11中, vector :: erase具有签名
iterator erase (const_iterator position);
, where the returned iterator points to the new position of the element after the element deleted. ,在删除元素后,返回的迭代器指向该元素的新位置。 My only solution is to pass a non-const iterator, copy all the elements after the given iterator back one position with a second iterator, and use a third iterator to store the original pointer position.
我唯一的解决方案是传递一个非常量迭代器,使用第二个迭代器将给定迭代器之后的所有元素复制回一个位置,然后使用第三个迭代器存储原始指针位置。 This requires three non-const iterator.
这需要三个非常量迭代器。
template <class T> typename Vec<T>::iterator Vec<T>::erase(iterator it)
{
iterator copy_iterator = it; // used to shift elements one position to the left past the deleted element.
iterator return_iterator = it; // holds original it position, per std implementation
while (it != (this -> end() - 1)) { // copies elements one position left
*copy_iterator++ = *++it;
}
alloc.destroy(it); // destroy last element in vector
avail = it; // shortens the vector by 1
return return_iterator;
}
Here avail is the iterator which points one past the end of the vector, ie iterator end() { return avail; }
这里的迭代器指向向量的末尾,即
iterator end() { return avail; }
iterator end() { return avail; }
. iterator end() { return avail; }
。 I don't see how any such function could take a const_iterator if it has to shift every element left by one, and I really don't like having three iterators. 我不知道如果必须将每个元素左移一个,那么这样的函数怎么会占用const_iterator,我真的不喜欢拥有三个迭代器。 Is there a better solution?
有更好的解决方案吗?
Additional Standards Question: 附加标准问题:
Up until C++98 , vector::erase took an iterator parameter. 直到C ++ 98为止 ,vector :: erase都使用了迭代器参数。 I am curious why this standard was changed.
我很好奇为什么要更改此标准。 In C++11, the erase functions includes what looks a direct conversion from const_iterator to iterator without any further explanation for why it is now const.
在C ++ 11中,擦除功能包括看起来从const_iterator到迭代器的直接转换,而无需进一步解释为什么现在是const。
template <class T> typename vector<T>::iterator erase(const_iterator __position) {
difference_type __ps = __position - cbegin();
pointer __p = this->__begin_ + __ps;
iterator __r = __make_iter(__p);
this->__destruct_at_end(_VSTD::move(__p + 1, this->__end_, __p));
return __r;
}
Here is a partial implementation of the Vec class: 这是Vec类的部分实现:
template <class T> class Vec {
public:
// typedefs
Vec() { create(); }
explicit Vec(std::size_t n, const T& val = T()) { create(n, val); }
Vec(const Vec& v) { create(v.begin(), v.end()); } // copy constructor
Vec& operator=(const Vec&);
~Vec() { uncreate(); } // destructor
T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }
void push_back(const T& val) {
if (avail == limit)
grow();
unchecked_append(val);
}
size_type size() const { return avail - data; }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return avail; }
const_iterator end() const { return avail; }
iterator erase(iterator);
private:
iterator data;
iterator avail;
iterator limit;
allocator<T> alloc;
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator); // calls alloc.allocate, then copies without default initialization
void uncreate(); // calls alloc.destroy on everything, then deallocates
void grow(); // allocates twice the memory
void unchecked_append(const T&);
};
Simply convert your const_iterator
to an iterator
within the function. 只需将
const_iterator
转换为iterator
内的iterator
。 Now, normally, this would be a no-no. 现在,通常,这是不可以的。 But since we know that the
Vec
is not const (because erase
is a non-const function), this is safe, unless the user passes an iterator that doesn't belong to the Vec
(which is not safe regardless). 但是由于我们知道
Vec
不是const(因为erase
是非const函数),因此这是安全的,除非用户通过了不属于Vec
的迭代器(无论如何都不安全)。
So, how to get a non-const iterator
from a const_iterator
? 那么,如何从
const_iterator
获取非常量iterator
呢? You could implement a private member in your const_iterator
class to do this and make the Vec
class a friend. 您可以在
const_iterator
类中实现一个私有成员,以使Vec
类成为朋友。 But since we're dealing with random access iterators, that is not necessary since we can just use iterator arithmetic. 但是,由于我们要处理随机访问迭代器,因此这是不必要的,因为我们可以使用迭代器算法。
// given a const_iterator cit
iterator it = begin() + (cit - begin());
I don't know the best answer to this but from what I can see you could re-derive a non-const pointer/iterator to the erase position using pointer arithmetic or do a legal const_cast
secure in the knowledge that your array is actually real (was created non-const
) because erase is a non-const function and could not be called on a const object. 我不知道最好的答案,但是从我的眼中可以看出,您可以使用指针算术将非const指针/迭代器重新推导到擦除位置,或者在知道数组实际上是真实的情况下进行合法的
const_cast
安全(创建为non-const
),因为擦除是一个非const函数,无法在const对象上调用。
template <class T> typename Vec<T>::iterator Vec<T>::erase(const_iterator it)
{
iterator non_const_it = this->begin() + std::distance(this->cbegin(), it);
iterator copy_iterator = non_const_it;
// etc...
return non_const_it;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.