簡體   English   中英

指向索引Vs迭代器的向量的指針

[英]pointer to vector at index Vs iterator

我有一個vector <Object> myvec ,我在我的代碼中使用它來保存內存中的對象列表。 我通過使用以“正常” C方式保持指向該向量中當前對象的指針

Object* pObj = &myvec[index];

這一切都工作正常如果... myvec不會變得足夠大以至於它在push_back中被移動,此時pObj變得無效 - 向量保證數據是順序的,因此他們不會努力將向量保持在相同的內存位置。

我可以為myvec保留足夠的空間以防止這種情況,但我不喜歡那種解決方案。

我可以保留所選myvec位置的索引,當我需要使用它時直接訪問它,但這對我的代碼來說是一個代價高昂的修改。

我想知道迭代器是否保持其引用完整,因為向量被重新分配/移動,如果可以,我只需要替換

Object* pObj = &myvec[index];

通過類似的東西

vector<Object>::iterator = myvec.begin()+index;

這有什么含義?

這可行嗎?

保存指向矢量位置指針的標准模式是什么?

干杯

不...使用迭代器你會遇到同樣的問題。 如果執行向量重新分配,則所有迭代器都將失效,並使用它們是未定義行為。

使用std::vector重新分配的唯一解決方案是使用整數索引。

使用例如std::list東西是不同的,但也有不同的效率妥協,所以它實際上取決於你需要做什么。

另一種選擇是創建自己的“智能索引”類,它存儲對向量和索引的引用。 這樣你就可以保持只傳遞一個“指針”(你可以為它實現指針語義)但代碼不會受到重新分配風險的影響。

迭代器(可能)被可能調整向量大小的任何東西(例如,push_back)無效。

但是,您可以創建自己的迭代器類來存儲向量索引,該索引在調整向量大小的操作中是穩定的:

#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>

namespace stable {

template <class T, class Dist=ptrdiff_t, class Ptr = T*, class Ref = T&>
class iterator : public std::iterator<std::random_access_iterator_tag, T, Dist, Ptr, Ref>
{
    T &container_;
    size_t index_;
public:
    iterator(T &container, size_t index) : container_(container), index_(index) {}

    iterator operator++() { ++index_; return *this; }
    iterator operator++(int) { iterator temp(*this); ++index_; return temp; }
    iterator operator--() { --index_; return *this; }
    iterator operator--(int) { stable_itertor temp(*this); --index_; return temp; }
    iterator operator+(Dist offset) { return iterator(container_, index_ + offset); }
    iterator operator-(Dist offset) { return iterator(container_, index_ - offset); }

    bool operator!=(iterator const &other) const { return index_ != other.index_; }
    bool operator==(iterator const &other) const { return index_ == other.index_; }
    bool operator<(iterator const &other) const { return index_ < other.index_; }
    bool operator>(iterator const &other) const { return index_ > other.index_; }

    typename T::value_type &operator *() { return container_[index_]; }
    typename T::value_type &operator[](size_t index) { return container_[index_ + index]; }
};

template <class T>
iterator<T> begin(T &container) { return iterator<T>(container, 0); }

template <class T>
iterator<T> end(T &container) { return iterator<T>(container, container.size()); }

}

#ifdef TEST
int main() { 

    std::vector<int> data;

    // add some data to the container:
    for (int i=0; i<10; i++)
        data.push_back(i);

    // get iterators to the beginning/end:
    stable::iterator<std::vector<int> > b = stable::begin(data);
    stable::iterator<std::vector<int> > e = stable::end(data);

    // add enough more data that the container will (probably) be resized:
    for (int i=10; i<10000; i++)
        data.push_back(i);

    // Use the previously-obtained iterators:
    std::copy(b, e, std::ostream_iterator<int>(std::cout, "\n"));

    // These iterators also support most pointer-like operations:
    std::cout << *(b+125) << "\n";
    std::cout << b[150] << "\n";

    return 0;
}
#endif

由於我們不能像普通迭代器類那樣將它作為嵌套類嵌入到容器內部,因此需要稍微不同的語法來聲明/定義此類型的對象; 而不是通常的std::vector<int>::iterator whatever; ,我們必須使用stable::iterator<std::vector<int> > whatever; 同樣,為了獲得容器的開頭,我們使用stable::begin(container)

有一點可能有點令人驚訝(至少在開始時):當你獲得一個stable::end(container) ,它會讓你在那個時候收到容器的末尾。 如上面的測試代碼所示,如​​果稍后向容器中添加更多項,則先前獲得的迭代器不會被調整以反映容器的新端 - 它保留了獲取它時的位置(即, 當時容器末端的位置,但不再是)。

不,矢量增長后迭代器無效。

解決這個問題的方法是保持索引到項目,而不是指針或迭代器。 這是因為該項目保持其索引,即使向量增長,當然假設您沒有在它之前插入任何項目(從而更改其索引)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM