C++ reference_wrapper 向量填充了错误的值

C++ reference_wrapper vector fills with wrong values

我正在尝试在 C++ 中使用引用包装器,因为我希望能够直接更改对象的值,但它们的值都是错误的。下面是一个演示此问题的示例:

#include <vector>
#include <functional>
#include <iostream>
using namespace std;

int main() {
    vector<int> v1 = {1, 2, 3};
    for (int i : v1) {
        cout << i << " ";
    }
    cout << endl;

    vector<reference_wrapper<int>> v2;
    for (int i : v1) {
        v2.push_back(i);
    }
    for (int i : v2) {
        cout << i << " ";
    }
}

它打印

1 2 3
3 3 3

我不确定为什么引用包装向量 v2 没有复制 v1 中的引用值...

编辑:这是另一个神秘地不起作用的例子。我认为这其中没有任何悬而未决的引用。

#include <vector>
#include <functional>
#include <iostream>
using namespace std;

int main() {
    vector<int> v1;
    vector<reference_wrapper<int>> v2;

    for (int i = 0; i < 3; i++) {
        v1.push_back(i);
        v2.push_back(v1[i]);
    }

    for (int i : v2) {
        cout << i << " ";
    }
}

它打印 9596312 1 2 而我希望它打印 0 1 2...

for循环中

for (int i : v1) {
    v2.push_back(i);
}

您正在从局部变量 i 构造 reference_wrappers,该变量在迭代后立即被销毁,因此存储在 v2 中的 reference_wrappers 是悬挂的。对它们的取消引用导致 undefined behavior.

您应该声明 i 作为参考

for (int& i : v1) {
    v2.push_back(i);
}

LIVE


对于您的编辑,请注意 std::vector::push_back 可能会导致 v1 上的重新分配,这会使存储在 v2 中的引用指向 v1 的元素。

您可以提前使用reserve以避免重新分配。例如

vector<int> v1;
v1.reserve(3);
vector<reference_wrapper<int>> v2;

for (int i = 0; i < 3; i++) {
    v1.push_back(i);
    v2.push_back(v1[i]);
}

LIVE

这个:

    vector<reference_wrapper<int>> v2;
    for (int i : v1) {
        v2.push_back(i);
    }

为每个 push_back 构造一个 reference_wrapper<int>。它将是对循环中 i 的引用。碰巧的是,您的编译器实现很可能碰巧为范围变量 i.

重用了相同的内存地址

引用在循环后仍会引用该地址 - 该地址在循环结束时恰好未被触及,因此最后一个值 i 就是存储在那里的值。

它导致程序通过引用(或任何其他方式)在该地址 read/write 具有未定义的行为,并且一种未定义的行为是您实际上可以读取内存并从中获取值似曾相识。

变量 i 在循环后失效,因此您应该以同样的方式处理对它的引用。都在风中飘荡...