【发布时间】:2023-03-07 14:20:02
【问题描述】:
如果我们对向量元素进行引用,然后调整向量的大小,则该引用不再有效,迭代器也是如此:
std::vector<int> vec{0, 1, 2, 3, 4, 5};
int& ref = vec[0];
auto itr = vec.begin();
cout << ref << " " << *itr << endl;
vec[0] = 7;
cout << ref << " " << *itr << endl;
vec.resize(100);
vec[0] = 3;
cout << ref << " " << *itr << endl;
打印出来:
0 0
7 7
0 0 // We expected a 3 here
而且我知道只保留对向量本身的引用并调用 vec[0] 会更实用,但只是为了提问,是否可以保留一个始终为 vec[0] 的对象] 即使对象被移动?
我已经尝试编写一个小的帮助类来帮助解决这个问题,但我不确定这是否是最好的方法,或者它是否会失败?
template<typename T>
struct HelperClass
{
std::vector<T>& vec;
size_t element;
HelperClass(std::vector<T>& vec_, size_t element_) : vec(vec_) , element(element_) {}
// Either define an implicit conversion from HelperClass to T
// or a 'dereference' operator that returns vec[0]
operator T&() { return vec.at(element); }
T& operator*() { return vec.at(element); }
};
并通过隐式转换为 T& 或“取消引用”运算符来使用它:
std::vector<int> vec{0, 1, 2, 3, 4, 5};
int& ref = vec[0];
auto itr = vec.begin();
HelperClass<int> hlp = HelperClass<int>(vec, 0); // HelperClass
cout << ref << " " << *itr << " " << hlp << " " << *hlp << endl;
vec[0] = 7;
cout << ref << " " << *itr << " " << hlp << " " << *hlp << endl;
vec.resize(100);
vec[0] = 3;
cout << ref << " " << *itr << " " << hlp << " " << *hlp << endl;
已经打印了例外的内容:
0 0 0 0
7 7 7 7
0 0 3 3
那么除了有一个辅助类之外还有更好的方法吗?辅助类在某些情况下是否不可靠?
我在reddit上也遇到过this的帖子,但是好像他们没有讨论那里的助手类
【问题讨论】:
-
引用是使用指针实现的。任何在内存中重新定位数据的操作都会使其无效,并且调整数组的大小可能需要重新分配。
-
@Barmar,是的,我只是问是否可以保留一个对象作为参考,当内存重新分配时不会失效,例如这个帮助类,我也有可能标题用错了,但我不确定什么是更好的标题。
-
使用方法也可以参考std::reference_wrapper。
-
看看
std::reference_wrapper和std::ref()。与传统参考不同,std::reference_wrapper可以反弹。因此,您可以获取对所需vector元素的引用,并在调整矢量大小后,再次获取对同一元素的新引用。 -
您的助手“工作”只是因为它通过索引而不是引用访问
vector。每次访问帮助程序时,它都会重新评估给定索引处的当前元素,只要该索引在调整大小后没有超出范围,就可以了。 STL 中的任何内容都不会为您做同样的事情,所以是的,您需要编写自己的助手来做您想做的事情。