【问题标题】:In C++, how can I get a pointer into a vector?在 C++ 中,如何获取指向向量的指针?
【发布时间】:2009-04-14 19:42:11
【问题描述】:

我正在编写一些 C++ 代码来操作一堆大小不断变化并因此不断重新分配的向量。

我想获得一个指向这些向量的“指针”,即使在重新分配向量后仍然有效。更具体地说,我只想让这些“指针”记住它们指向的向量以及它们指向的索引。当我使用标准 (*ptr) 语法取消引用它们时,我只想让它们进行明显的查找。

显然,实际指针在重新分配后将无效,我的理解是迭代器在重新分配后也无效。另请注意,我不关心元素是否插入到我的对象之前,因此这些“指针”实际上不需要记住任何东西,只需要一个向量和一个索引。

现在,我自己可以轻松编写这样的课程。有人(Boost?STL?)已经为我做过了吗?

编辑:答案没有解决我的问题。 我问这个功能是否是任何标准库。我认为答案是“否”?

【问题讨论】:

  • 附言。如果这是一个愚蠢/重复的问题,如果有人提供参考,我很乐意将其删除。谢谢!
  • 您有什么理由不能为此使用 std::vector 吗?
  • 显然,因为他不仅要保留向量,还要保留向量中的位置。如果向量从未重新分配,他会想要一个迭代器。想想“vector bar; Myiterator mi(bar, 3);”所以 *mi 永远是 bar[3]。
  • 你需要一个 bool* 到 std::vector 吗?可能会很痛苦
  • 我认为标准库(STL 和 Boost)中没有解决方案。

标签: c++ pointers vector


【解决方案1】:

尝试 std::pair,因为向量的位置和元素的索引都不会改变。
或者,作为一个班级:

template<class T> class VectorElementPointer
{
  vector<T>& vectorref;
  typename vector<T>::size_type index;
public:
  VectorElementPointer(vector<T>& vref, typename vector<T>::size_type index):vectorref(vref),index(index){}
  T& operator*() const {return vectorref[index];}
  T* operator->() const {return &vectorref[index];}
};

这是我想到的最简单的解决方案,因为 STL 和 Boost 都不包含任何更容易做到的东西。

【讨论】:

  • +1 - 打败我。我建议的唯一改进是使 vectorptr 成为引用而不是指针。
  • 您还需要其他运算符吗?
  • 但请记住使用 size_t 而不是 int! (显然使用正确的模板语法)
  • 您可能希望扩展为具有 RandomAccessIterator 语义
  • 可能不得不为读者留下一些练习。 ;v)
【解决方案2】:
【解决方案3】:

总结一些想法。这是一个极简包装器,它试图模仿迭代器,但与向量的迭代器相反,它仍然有效。

void print(const std::string& i)
{
    std::cout << "<" << i << "> ";
}
int main()
{
    typedef std::vector<std::string> Vector;

    Vector v;
    v.push_back("H");
    v.push_back("E");
    v.push_back("W");
    StrongIterator<Vector> it0(v, 0);
    StrongIterator<Vector> it3(v, v.end());

    std::for_each(it0.it(), it3.it(), print);
    std::cout << std::endl;

    v.push_back("O");
    std::for_each(it0.it(), it3.it(), print);

    std::cout << *it0;
    std::cout << it0->c_str();

    return 0;
}

还有迭代器本身。

template <typename TVector>
class StrongIterator
{
public:
    typedef typename TVector::iterator iterator;
    typedef typename TVector::size_type size_type;
    typedef typename TVector::value_type value_type;
    StrongIterator(TVector& vector,
                   size_type index):
        vector_(vector),
        index_(index)
    {}
    StrongIterator(TVector& vector,
                   iterator it):
        vector_(vector),
        index_(std::distance(vector.begin(), it))
    {}
    iterator it()
    {
        iterator it = vector_.begin();
        std::advance(it, index_);
        return it;
    }
    value_type& operator*()
    {
        return vector_[index_];
    }
    value_type* operator->()
    {
        return &vector_[index_];
    }
private:
    TVector& vector_;
    size_type index_;
};

【讨论】:

    【解决方案4】:

    不幸的是,一旦您修改了向量,将不再保证“指向”向量元素的迭代器是有效的。我所知道的唯一 STL 结构即使在结构发生变化时也能保持迭代器有效是 list。如果您只想对结构进行顺序迭代,则可以使用 std::list 否则我不知道任何其他可以帮助您的库;这并不意味着没有。

    这里有一些关于 std::list 的清晰文档:http://www.cplusplus.com/reference/stl/list/

    【讨论】:

    • map 和 set 也保留有效的迭代器。
    【解决方案5】:

    使用boost::iterator_facade

    // Warning: Untested, not even compiled
    template<class VectorT>
    class VectorIndex : 
        public boost::iterator_facade<VectorIndex, typename VectorT::reference, boost::random_access_traversal_tag>
    {
    public:
        VectorIndex(VectorT& Vec, typename VectorT::size_type Index)
        : m_Vec(Vec), m_Index(Index)
        {
        }
    
    private:
        friend class boost::iterator_core_access;
    
        void increment()
        {
            ++m_Index;
        }
    
        void decrement()
        {
            --m_Index;
        } 
    
        void advance(difference_type N)
        {
            m_Index += N;
        }
    
        difference_type distance_to(const VectorIndex& Other)
        {
            assert(&this->m_Vec == &Other.m_Vec);
            return Other.m_Index = this->m_Index; 
        }
    
        bool equal(const VectorIndex& Other)const
        {
            return (this->m_Vec == Other.m_Vec)
                && (this->m_Index == Other.m_Index);
        }
    
        VectorT::reference dereference() const 
        {
            return m_Vec[m_Index];
        }
    
        VectorT m_Vec;
        VectorT::size_type m_Index;
    };
    

    【讨论】:

      【解决方案6】:

      除非您编写自己的向量和智能指针版本,否则指针在重新分配后不会有效。如果您有自己的实现,智能向量可以向您的智能指针发送通知。

      但是我认为整个场景的设计很糟糕,您最好重新设计您的场景,这样您就没有这样的要求了。

      【讨论】:

        【解决方案7】:

        根据您的使用模式,std::deque 可能满足您的要求。仅当您插入或删除不在开头或结尾的项目时,指向双端队列的指针才会失效 - 换句话说, push_front() 和 push_back() 不会使指向双端队列的指针失效,但其他更改会。你得到了与向量基本相同的接口,但当然底层存储是不连续的。

        【讨论】:

        • 我觉得很奇怪有人否决了这个答案。 (我赞成平衡。)在我的情况下,我只使用双端队列操作,并且深度指针指向双端队列的属性会很有用,即使它没有直接解决我的问题。所以谢谢!
        猜你喜欢
        • 2019-09-10
        • 2020-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-04
        • 2020-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多