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 );
}
};