简体   繁体   English

如何为向量实现std :: erase?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM