如何在下面的某个向量实现中避免数组订阅运算符中的悬空引用?如果realloc
更改指针,则先前从operator []获取的引用不再有效。我不能使用new / delete。我必须使用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_.push_back(v_[id]);
其中v_是Vector的实例。为了防止这种情况,新的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;
}
}
答案 0 :(得分:4)
基本上你可以做三件事:
v[42] = "Hello"
)。在这种情况下,您需要一个operator[]
标记为const
。const T&
向代理添加一个赋值,以允许写入向量的元素,并且您需要提供一些访问/读取值的方法,很可能是隐式operator const 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 );
}
};
请注意,上述内容不完整,整个技术存在一些缺点。最重要的问题是API中的代理“泄漏”,因此不符合某些用例。您需要根据您的环境调整技术,看它是否适合。