gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 01:07:43 24 4
gpt4 key购买 nike

如何在下面的一些 vector 实现中避免数组订阅运算符中的悬空引用?如果 realloc 更改了指针,那么之前从 operator[] 获得的引用将不再有效。我不能为此使用新/删除。我必须使用 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;
}
}

最佳答案

基本上您可以做三件事:

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

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

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 中的代理“泄漏”,因此不满足某些用例。您需要使该技术适应您的环境,看看它是否适合。

关于c++ - 避免数组订阅运算符中的悬空引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18974612/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com