当我这样做时:
std::vector<int> hello;
一切都很好。但是,当我将其设为引用向量时:
std::vector<int &> hello;
我得到可怕的错误,比如
错误 C2528:“指针”:指向引用的指针非法
我想将一堆对结构的引用放入一个向量中,这样我就不必干预指针了。为什么vector会为此发脾气?我唯一的选择是使用指针向量吗?
矢量等容器的组件类型必须为 assignable。引用是不可分配的(您只能在声明它们时初始化它们一次,并且以后不能让它们引用其他东西)。其他不可分配的类型也不允许作为容器的组件,例如 vector<const int>
是不允许的。
是的,您可以,寻找 std::reference_wrapper
,它模仿参考,但可分配,也可以“重新安装”
get()
?例如 reference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff();
不是很像。
.get()
。 timdiels 想要的是 operator.
;查看有关此的最新提案/讨论。
reference_wrapper
与原始引用类型不同,可以“重新安装”它,但它仍然不能未初始化,因此它不是默认可构造的。这意味着虽然可以构造 vector<reference_wrapper<int>>{int1, int2, int3}
,但仍然不能拥有带有默认构造元素的向量:vector<reference_wrapper<int>>(5)
。这甚至没有被 IDE (CLion) 捕获,但编译失败。
<functional>
中声明很奇怪——它似乎比仅仅可调用对象更通用。
就其本质而言,引用只能在创建时设置;即,以下两行具有非常不同的效果:
int & A = B; // makes A an alias for B
A = C; // assigns value of C to B.
此外,这是非法的:
int & D; // must be set to a int variable.
但是,当您创建向量时,无法在创建时为其项目分配值。您实际上只是在制作最后一个示例。
Ion Todirel 已经使用 std::reference_wrapper
提到了答案YES。 自 C++11 起,我们有一种从 std::vector
检索对象并使用 std::remove_reference
删除引用的机制。下面给出了一个使用 g++
和 clang
以及选项 -std=c++11
编译并成功执行的示例。
#include <iostream>
#include <vector>
#include <functional>
class MyClass {
public:
void func() {
std::cout << "I am func \n";
}
MyClass(int y) : x(y) {}
int getval() {
return x;
}
private:
int x;
};
int main() {
std::vector<std::reference_wrapper<MyClass>> vec;
MyClass obj1(2);
MyClass obj2(3);
MyClass& obj_ref1 = std::ref(obj1);
MyClass& obj_ref2 = obj2;
vec.push_back(obj_ref1);
vec.push_back(obj_ref2);
for (auto obj3 : vec) {
std::remove_reference<MyClass&>::type(obj3).func();
std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n";
}
}
std::remove_reference<>
中的值。 std::remove_reference<>
的要点是允许您编写“类型 T,但如果它是一个则不是引用”。所以 std::remove_reference<MyClass&>::type
与写 MyClass
是一样的。
for (MyClass obj3 : vec) std::cout << obj3.getval() << "\n";
(或者如果你声明 getval()
const,你应该写 for (const MyClass& obj3: vec)
)。
TL;博士
像这样使用 std::reference_wrapper
:
#include <functional>
#include <string>
#include <vector>
#include <iostream>
int main()
{
std::string hello = "Hello, ";
std::string world = "everyone!";
typedef std::vector<std::reference_wrapper<std::string>> vec_t;
vec_t vec = {hello, world};
vec[1].get() = "world!";
std::cout << hello << world << std::endl;
return 0;
}
长答案
作为 standard suggests,对于包含 T
类型的对象的标准容器 X
,T
必须是来自 X
的 Erasable
。
Erasable
表示以下表达式格式正确:
allocator_traits<A>::destroy(m, p)
A
是容器的分配器类型,m
是分配器实例,p
是 *T
类型的指针。有关 Erasable
的定义,请参见 here。
默认情况下,std::allocator<T>
用作向量的分配器。使用默认分配器,要求等同于 p->~T()
的有效性(注意 T
是引用类型,p
是指向引用的指针)。但是,pointer to a reference is illegal,因此表达式的格式不正确。
这是 C++ 语言的一个缺陷。您不能获取引用的地址,因为尝试这样做会导致引用对象的地址,因此您永远无法获得指向引用的指针。 std::vector
使用指向其元素的指针,因此存储的值需要能够被指向。您将不得不使用指针。
sizeof
作为参考。
boost::ptr_vector<int>
将起作用。
编辑: 是使用 std::vector< boost::ref<int> >
的建议,因为您不能默认构造 boost::ref
,所以它不起作用。
resize
。
正如其他人所提到的,您最终可能会改用指针向量。
但是,您可能需要考虑改用 ptr_vector!
我在 C++14 中找到了原因,“国际标准 ISO/IEC 14882:2014(E) 编程语言 C++”
[8.3.2-5.s1] 不应该有对引用的引用,没有引用数组,也没有指向引用的指针。
正如其他评论所暗示的那样,您仅限于使用指针。但如果它有帮助,这里有一种避免直接面对指针的技术。
您可以执行以下操作:
vector<int*> iarray;
int default_item = 0; // for handling out-of-range exception
int& get_item_as_ref(unsigned int idx) {
// handling out-of-range exception
if(idx >= iarray.size())
return default_item;
return reinterpret_cast<int&>(*iarray[idx]);
}
reinterpret_cast
不需要
不定期副业成功案例分享