如何通过引用推送向量?

Posted

技术标签:

【中文标题】如何通过引用推送向量?【英文标题】:How do I push vectors by reference? 【发布时间】:2018-11-09 21:59:15 【问题描述】:

下面的代码不起作用,因为我将向量 a 和 b 推回向量向量,然后更改向量 a 和 b。我想改变向量 a 和 b 以便向量向量遭受相同的修改。我该怎么做?

#include <iostream>
#include <vector>

int main()

std::vector<std::vector<int>>vector;
std::vector<int>a;
std::vector<int>b;
vector.push_back(a);
vector.push_back(b);
for (int i = 1; i <= 10; i++)
    a.push_back(i);
for (int i = 11; i <= 20; i++)
    b.push_back(i);
std::cout << vector[1][0];
std::cin.get();

【问题讨论】:

直接使用向量 - 例如vector[0].push_back(i) 在第一个循环中,而不是 a.push_back(i) 【参考方案1】:

您可以使用std::reference_wrapper(C++11 起)。

std::reference_wrapper 是一个类模板,它将引用包装在可复制、可分配的对象中。它经常被用作在标准容器(如std::vector)中存储引用的机制,这些容器通常不能保存引用。

例如

std::vector<std::reference_wrapper<std::vector<int>>> v;
std::vector<int> a;
std::vector<int> b;
v.push_back(a);
v.push_back(b);
for (int i = 1; i <= 10; i++)
    a.push_back(i);
for (int i = 11; i <= 20; i++)
    b.push_back(i);
std::cout << v[1].get()[0]; //11

LIVE

请注意,如果vector 的寿命比ab 更长,那么当ab 被销毁时,存储在vector 中的引用会变得悬空。

【讨论】:

这里的一个问题是v 在超出范围后包含对ab 的引用。【参考方案2】:

创建vvector 不是一个好名字,因为它与库共享并使代码混乱)成为vector 指针的vector(因为a vector of references is not possible):

std::vector<std::vector<int> *> v; //declare as vec of vec pointers
...
v.push_back(&a); //push_back addresses of a and b
v.push_back(&b);
...
std::cout << v.at(1)->at(0) //dereference and call at on the inner vec

请注意,如果 abv 之前超出范围,这可能会很危险,因为这会给您留下悬空指针、一堆未定义的行为和一个谋杀耗时的错误。

【讨论】:

如果向量(或它的副本)超过ab,这是很危险的,因为它将包含悬空引用。【参考方案3】:

基本问题是push_back 将其参数复制到向量的末尾。要修改向量中的对象,您需要获取对它的引用。一种方法:

std::vector< std::vector<int> > my_vector;
my_vector.reserve(2);  // Going over the allocation invalidates references

my_vector.push_back( std::vector<int>() );
std::vector<int> & a = my_vector.back();

my_vector.push_back( std::vector<int>() );
std::vector<int> & b = my_vector.back();

(我更改了变量的名称,因为使用“vector”作为变量名容易导致混淆。)

如果可以使用 C++17,有一种方法可以使用 emplace_back 减少代码行数。

【讨论】:

emplace_back 也存在于 C++11 和 C++14 中。 @Matt true,但是在C++17之前,它的返回类型是void 请小心,因为如果第二个push_back 增加了向量的容量,则从之前的back() 获得的引用将失效。 @JaMiT 非常正确,我没有看到你要去哪里,但现在很清楚了。 @RemyLebeau 好点。我添加了预订以避免这种情况。而且我承认可能有更好的方法来做事;在没有大局的情况下选择一个是很难的。【参考方案4】:

如果你提前知道向量的数量,你可以这样做:

std::vector<std::vector<int>> v(2);
std::vector<int> &a = v[0];
std::vector<int> &b = v[1];
...

【讨论】:

以上是关于如何通过引用推送向量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中通过引用返回向量

C++:试图理解通过引用传递向量

通过引用将向量对象传递给函数? [关闭]

通过引用传递向量的 typedef 向量

如何访问在 C++ 中通过引用传递的列表/向量的元素

通过引用传递向量内联