C++ 避免数组订阅运算符中的悬空引用

C++ 避免数组订阅运算符中的悬空引用,c++,arrays,vector,C++,Arrays,Vector,在下面的一些向量实现中,如何避免在数组订阅运算符中挂起引用?如果realloc更改指针,则先前从运算符[]获取的引用将不再有效。我无法对此使用“新建/删除”。我必须使用malloc/realloc/free template <class T> class Vector { public: typedef size_t size_type_; ... T& operator[] (const size_type_); void push_back (c

在下面的一些向量实现中,如何避免在数组订阅运算符中挂起引用?如果
realloc
更改指针,则先前从运算符[]获取的引用将不再有效。我无法对此使用“新建/删除”。我必须使用
malloc
/
realloc
/
free

template <class T>
class Vector
{
  public:
  typedef size_t size_type_;

  ...

  T& operator[] (const size_type_);
  void push_back (const T&);

  ...

  private:
  const size_type_ page_size_;
  size_type_ size_;
  size_type_ capacity_;
  T* buffer_;
};


template<class T>
inline
T&
some_namespace::Vector<T>::operator[] (const size_type_ index)
{
  ASSERT(index < size_);
  return buffer_[index];
}


template<class T>
inline
void
some_namespace::Vector<T>::push_back(const T& val)
{
  if (size_ >= capacity_)
  {
    capacity_ += page_size_;
    T* temp = (T*)(realloc(buffer_, capacity_*sizeof(T)));

    if (temp != NULL)
    {
      buffer_ = temp;
    }
    else
    {
      free(buffer_);
      throw some_namespace::UnexpectedEvent();
    }
  }

  buffer_[size_++] = val;
}
其中v_u是向量的一个实例。为防止出现这种情况,新推出的push_back是:

template<class T>
inline
void
some_namespace::Vector<T>::push_back(const T& val)
{
  if (size_ >= capacity_)
  {
    const T val_temp = val; // copy val since it may come from the buffer_
    capacity_ += page_size_;
    T* temp = (T*)(realloc(buffer_, capacity_*sizeof(T)));

    if (temp != NULL)
    {
      buffer_ = temp;
    }
    else
    {
      free(buffer_);
      throw some_namespace::UnexpectedEvent();
    }

    buffer_[size_++] = val_temp;
  }
  else
  {
    buffer_[size_++] = val;
  }
}
模板
内联
无效的
一些名称空间::向量::推回(const T&val)
{
如果(尺寸=容量)
{
const T val_temp=val;//复制val,因为它可能来自缓冲区_
容量\+=页面大小\;
T*temp=(T*)(realloc(缓冲区,容量大小(T));
如果(温度!=NULL)
{
缓冲区=温度;
}
其他的
{
自由(缓冲区);
抛出一些名称空间::UnexpectedEvent();
}
缓冲区\[size\+]=val\u temp;
}
其他的
{
缓冲区\[size \++]=val;
}
}

基本上可以做三件事:

  • 按原样接受并记录它。这就是STL所做的,它实际上是相当合理的
  • 不返回引用,返回副本。当然,这意味着您不能再为向量的元素赋值(
    v[42]=“Hello”
    )。在这种情况下,您需要一个标记为
    const
    操作符[]
  • 返回一个代理对象,该对象存储对向量本身和索引的引用。您可以从
    常量T&
    向代理添加赋值,以允许写入向量的元素,并且需要提供某种方式来访问/读取值,很可能是隐式
    运算符常量T&
    。由于代理对象在每次访问时向向量询问元素的当前位置,因此即使向量在调用之间更改了这些元素的位置,这种方法也会起作用。只要小心多线程

以下是代理的草图,未经测试且不完整:

template<typename T> class Vector
{
private:
    // ...

    // internal access to the elements
    T& ref( const size_type_ i );
    const T& ref( const size_type_ i ) const;

    class Proxy
    {
    private:
        // store a reference to a vector and the index
        Vector& v_;
        size_type_ i_;

        // only the vector (our friend) is allowed to create a Proxy
        Proxy( Vector& v, size_type_ i ) : v_(v), i_(i) {}
        friend class Vector;

    public:
        // the user that receives a Proxy can write/assign values to it...
        Proxy& operator=( const T& v ) { v_.ref(i_) = v; return *this; }

        // ...or the Proxy can convert itself in a value for reading
        operator const T&() const { return v_.ref(i_); }
    };

    // the Proxy needs access to the above internal element accessors
    friend class Proxy;

public:
    // and now we return a Proxy for v[i]
    Proxy operator[]( const size_type_ i )
    {
        return Proxy( *this, i );
    }
};
模板类向量
{
私人:
// ...
//对要素的内部访问
T&ref(常数尺寸和类型);
常数T&ref(常数尺寸和类型)常数;
类代理
{
私人:
//存储对向量和索引的引用
向量&v;
尺寸u类型ui;
//只允许向量(我们的朋友)创建代理
代理(Vector&v,size_type_i):v_v(v),i_u(i){
友元类向量;
公众:
//接收代理的用户可以向其写入/分配值。。。
Proxy&operator=(const T&v){v_.ref(i_)=v;return*this;}
//…或者代理可以将自身转换为值以进行读取
运算符常量T&()常量{return v_u.ref(i_u);}
};
//代理需要访问上述内部元素访问器
朋友类代理;
公众:
//现在我们返回v[i]的代理
代理运算符[](常量大小\类型\ i)
{
返回代理(*本,i);
}
};

请注意,以上内容是不完整的,并且整个技术有一些缺点。最重要的问题是API中的代理“泄漏”,因此一些用例没有得到满足。您需要根据您的环境调整该技术,看看是否适合。

谢谢:-)。代理听起来很有趣。你能给我一个代码片段吗?@user1806925我现在正在烧烤,稍后会为代理添加一个草图…@user1806925按照承诺,我添加了一个草图。希望有帮助。谢谢!今晚我会尝试整合它。我会让你知道的。STL向量不包括悬挂引用?在分配内存之前,我在下面有一个STL向量。他工作得很好。我猜分配规模更大?
template<typename T> class Vector
{
private:
    // ...

    // internal access to the elements
    T& ref( const size_type_ i );
    const T& ref( const size_type_ i ) const;

    class Proxy
    {
    private:
        // store a reference to a vector and the index
        Vector& v_;
        size_type_ i_;

        // only the vector (our friend) is allowed to create a Proxy
        Proxy( Vector& v, size_type_ i ) : v_(v), i_(i) {}
        friend class Vector;

    public:
        // the user that receives a Proxy can write/assign values to it...
        Proxy& operator=( const T& v ) { v_.ref(i_) = v; return *this; }

        // ...or the Proxy can convert itself in a value for reading
        operator const T&() const { return v_.ref(i_); }
    };

    // the Proxy needs access to the above internal element accessors
    friend class Proxy;

public:
    // and now we return a Proxy for v[i]
    Proxy operator[]( const size_type_ i )
    {
        return Proxy( *this, i );
    }
};